echo $(echo 66 85 84 84 83 | awk '{for(i=1;i<=NF;i++) printf "%c", $i}')
Author: Derrick
-

Bash Script: Calculate before/after 2: Calculate Harder
As an update, or an evolution of my earlier script that did some simple math for me, I’ve made one that will full-on test a URL while I’m making changes to see what the impact performance is of my updates.
$ abtesturl.sh --url=https://example.com/ --count=10 Press any key to run initial tests... Initial average TTFB: 3.538 seconds Press any key to re-run tests... Running second test... Second average TTFB: 1.975 seconds Before TTFB: 3.538 seconds After TTFB: 1.975 seconds Change in TTFB: -1.563 seconds Percentage Change: -44.00%Code language: JavaScript (javascript)It makes it much simpler to gather data to write reports or figure out of a change is worth the effort.
Well, that’s about it so here’s the script:
#!/bin/bash function show_usage() { echo "Usage: $0 --url=<URL> [--count=<number of requests>]" echo " --url Specifies the URL to test." echo " --count Optional. Specifies the number of requests to send. Default is 6." echo echo "Example: $0 --url=https://example.com/ --count=5" exit } function average_ttfb() { local URL="" local COUNT=6 # Default COUNT to 6 if not supplied local CURL_OPTS="-s" # Parse arguments for arg in "$@"; do case $arg in --url=*) URL="${arg#*=}" shift # Remove argument from processing ;; --count=*) COUNT="${arg#*=}" shift # Remove argument from processing ;; *) # Unknown option ;; esac done if [[ -z "$URL" ]]; then exit 1 fi local total_time=0 local count_success=0 for ((i=1; i<=COUNT; i++)) do # Perform the curl command, extracting the time to first byte ttfb=$(curl $CURL_OPTS -o /dev/null -w "%{time_starttransfer}\n" $URL) # Check if the curl command was successful if [ $? -eq 0 ]; then total_time=$(echo "$total_time + $ttfb" | bc) ((count_success++)) else echo "Request $i failed." >&2 fi done if [ $count_success -eq 0 ]; then echo "All requests failed." >&2 return 1 fi # Calculate the average TTFB average_time=$(echo "scale=3; $total_time / $count_success" | bc) echo $average_time # This line now simply outputs the average time } function ab_test_ttfb() { # Run initial test read -p "Press any key to run initial tests..." -n 1 -r initial_ttfb=$(set -e; average_ttfb "$@"; set +e) echo "Initial average TTFB: $initial_ttfb seconds" # Wait for user input to proceed read -p "Press any key to re-run tests..." -n 1 -r echo # Move to a new line # Run second test echo "Running second test..." second_ttfb=$(average_ttfb "$@") echo "Second average TTFB: $second_ttfb seconds" # Calculate and output the difference and percentage change difference=$(echo "$second_ttfb - $initial_ttfb" | bc) percent_change=$(echo "scale=2; ($difference / $initial_ttfb) * 100" | bc) echo "Before TTFB: $initial_ttfb seconds" echo "After TTFB: $second_ttfb seconds" echo "Change in TTFB: $difference seconds" echo "Percentage Change: $percent_change%" } # Check if help is requested or no arguments are provided if [[ " $* " == *" --help "* ]] || [[ "$#" -eq 0 ]]; then show_usage fi # Check if --url is in the arguments url_present=false for arg in "$@"; do if [[ $arg == --url=* ]]; then url_present=true break fi done if [ "$url_present" = false ]; then echo "Error: --url argument is required." show_usage fi ab_test_ttfb "$@"Code language: Bash (bash)Don’t break anything!
-

Code Sweep: A Simple Approach to a Neater WordPress User List
Feel like clearing out your spam users? With the snippet below we can make your job much easier!
/** * Adds a new column to the user management screen for displaying the number of comments. * * @param array $columns The existing columns in the user management screen. * * @return array The modified columns array with the new 'comments_count' column added. */ function emrikol_add_comments_column( array $columns ): array { $columns['comments_count'] = esc_html__( text: 'Comments', domain: 'default' ); return $columns; } add_filter( 'manage_users_columns', 'emrikol_add_comments_column' ); /** * Displays the number of comments for a user in the custom column. * * @param string $output The value to be displayed in the column. * @param string $column_name The name of the custom column. * @param int $user_id The ID of the user. * * @return string The updated value to be displayed in the column. */ function emrikol_show_comments_count( string $output, string $column_name, int $user_id ): string { if ( 'comments_count' == $column_name ) { $args = array( 'user_id' => $user_id, 'count' => true, ); $comments_count = get_comments( args: $args ); return number_format_i18n( number: $comments_count ); } return $output; } add_action( 'manage_users_custom_column', 'emrikol_show_comments_count', 10, 3 );Code language: PHP (php)This will add a “Comments” count to the WordPress user list so you can easily determine which users you can delete:

What a sad state this blarg is in…
-

Matrix Reimagined: Crafting Digital Rain with Bash and ChatGPT
Just for fun, and I have no idea why I thought about it, I decided to work with ChatGPT (4) to build a simple bash-based version of the Matrix Digital Rain. I know there’s already better versions, like cmatrix, but we do not do things because they are easy. We do them because we are bored.

I’ve asked ChatGPT to heavily comment the code for us so that we can see exactly what’s going on:
#!/bin/bash # This script creates a Matrix-style falling text effect in the terminal. # Define strings for extra characters (Japanese Katakana) and extended ASCII characters extra_chars="カキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン" extended_ascii="│┤┐└┴┬├─┼┘┌≡" # Define arrays of color codes for a fading green color effect, and a static color fade_colors=('\033[38;2;0;255;0m' '\033[38;2;0;192;0m' '\033[38;2;0;128;0m' '\033[38;2;0;64;0m' '\033[38;2;0;32;0m' '\033[38;2;0;32;0m' '\033[38;2;0;32;0m' '\033[38;2;0;32;0m' '\033[38;2;0;32;0m' '\033[38;2;0;32;0m' '\033[38;2;0;32;0m' '\033[38;2;0;32;0m' '\033[38;2;0;32;0m' '\033[38;2;0;32;0m' '\033[38;2;0;32;0m' '\033[38;2;0;32;0m' '\033[38;2;0;32;0m' '\033[38;2;0;32;0m' '\033[38;2;0;32;0m' '\033[38;2;0;32;0m' '\033[38;2;0;16;0m' '\033[38;2;0;8;0m') # Fading green colors static_color='\033[38;2;0;0;0m' # Static dark green color white_bold='\033[1;37m' # White and bold for the primary character # Get terminal dimensions COLUMNS=$(tput cols) # Number of columns in the terminal ROWS=$(tput lines) # Number of rows in the terminal # Hide the cursor for a cleaner effect and clear the screen echo -ne '\033[?25l' clear # Function to generate a random character from the set of extra characters and extended ASCII random_char() { local chars="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789${extra_chars}${extended_ascii}" echo -n "${chars:RANDOM%${#chars}:1}" } # Generate a list of 1000 random characters random_chars="" for (( i=0; i<1000; i++ )); do random_chars+=$(random_char) # Add a random character to the end of the string done # Initialize a counter for cycling through the random characters char_counter=0 # Counter for cycling through the random characters # Initialize arrays to keep track of the position and trail characters of each column positions=() # Array to store the current position in each column trail_chars=() # Array to store the trail characters in each column for (( c=1; c<=COLUMNS; c++ )); do positions[$c]=$((RANDOM % ROWS)) # Random starting position for each column trail_chars[$c]="" # Start with an empty trail for each column done # Function to update the display with the falling text effect update_line() { local last_pos=0 # Track the last position to optimize cursor movement for (( c=1; c<=COLUMNS; c++ )); do # Randomly skip updating some columns to create a dynamic effect if [ $((RANDOM % 4)) -ne 0 ]; then continue fi local new_char=${random_chars:$char_counter:1} # Select the next character from the random string char_counter=$(( (char_counter + 1) % 1000 )) # Update the counter, cycling back after 1000 local pos=${positions[$c]} # Current position in this column local trail=${trail_chars[$c]} # Current trail of characters in this column trail_chars[$c]="${new_char}${trail:0:$((ROWS - 1))}" # Update the trail by adding new character at the top # Render the trail of characters for (( i=0; i<${#trail}; i++ )); do local trail_pos=$((pos - i)) # Calculate the position for each character in the trail if [ $trail_pos -ge 0 ] && [ $trail_pos -lt $ROWS ]; then local color=${fade_colors[i]:-$static_color} # Choose color from the fade array or static color if beyond the array if [ $i -eq 0 ]; then color=$white_bold # First character in the trail is white and bold fi if [ $last_pos -ne $trail_pos ]; then printf "%b" "\033[${trail_pos};${c}H" # Move cursor to the right position last_pos=$trail_pos fi printf "%b" "${color}${trail:$i:1}\033[0m" # Print the character with color fi done positions[$c]=$((pos + 1)) # Update the position for the next cycle if [ $pos -ge $((ROWS + ${#fade_colors[@]})) ]; then positions[$c]=0 # Reset position if it moves off screen trail_chars[$c]="" fi done } # Main loop for continuous execution of the update_line function while true; do update_line done # Reset terminal settings on exit (show cursor, clear screen, reset text format) echo -ne '\033[?25h' # Show cursor clear tput sgr0 # Reset text formatCode language: PHP (php)Challenges Faced
Developing the Matrix Digital Rain script presented specific challenges, especially in terms of performance. The initial use of
tputfor cursor manipulation proved inefficient for the dynamic text display. This issue was resolved by switching toprintfand ANSI escape sequences, which significantly enhanced the rendering performance.Another problem arose with the use of fullwidth Katakana characters, which were incompatible with monospaced fonts, disrupting the visual flow. The solution involved adopting halfwidth Katakana, ensuring better compatibility and preserving the uniformity essential for the Matrix-style effect.
Another notable challenge emerged in development: the inefficiency of generating random characters on the fly. Due to Bash’s slower handling of string functions, this method significantly hindered performance. To tackle this, a strategic shift was made from real-time character generation to utilizing a predefined lookup table.
This approach involved generating a large set of pseudorandom characters before entering the main loop of the program. By doing so, I could rapidly access this table during runtime, boosting performance. This change played a crucial role in maintaining fluidity and responsiveness. It also preserved the illusion of randomness, essential for the authentic Matrix effect, thus striking a balance between performance efficiency and visual fidelity.
If you’d like to see what it looks like, here’s an example:
So yeah. That’s it I guess? Enjoy!
-

Quick Tip: Add Screen Name to Bash Prompt
I often SSH into servers to get some work done, and one of the things I discovered recently is that I may not always know or remember if I’m in a screen session.
So I had the bright idea to just add it to my shell prompt!

Simply just add one of these to your RC file of choice:
Bash
# Add Screen name to PS1 if we're in a screen. if [ -n "$STY" ]; then PS1="\[\e[1m\](Screen: $STY)\[\e[0m\]\n$PS1" fiCode language: PHP (php)ZSH
# Add Screen name to PROMPT if we're in a screen. if [[ -n "$STY" ]]; then PROMPT="%B(Screen: $STY)%b"$'\n'"$PROMPT" fiCode language: PHP (php)And remember, if you’re asking yourself if you should run something in a screen, you’re already too late!
-

Bash Script: Calculate before/after averages
I’ve been doing some performance testing, and wanted a quick way to test how well or poorly changes affect a site. Normally I’d whip out the ol’ calculator app and do this manually. That got tiring after a while, so instead with the help of ChatGPT, I made this little bash script that will do the work for you:
#!/bin/bash # Function to calculate the average of a list of numbers average() { local sum=0 local count=0 for num in "$@"; do sum=$(echo "$sum + $num" | bc -l) count=$((count+1)) done echo "$sum / $count" | bc -l } # Parse arguments for i in "$@"; do case $i in --before=*) BEFORE="${i#*=}" shift ;; --after=*) AFTER="${i#*=}" shift ;; *) # unknown option ;; esac done # Check if both BEFORE and AFTER parameters are provided if [ -z "$BEFORE" ] || [ -z "$AFTER" ]; then echo "Error: Missing required parameters." echo "Usage: $0 --before=<comma-separated-values> --after=<comma-separated-values>" exit 1 fi IFS=',' read -ra BEFORE_LIST <<< "$BEFORE" IFS=',' read -ra AFTER_LIST <<< "$AFTER" # Calculate average for before and after lists BEFORE_AVG=$(printf "%.2f\n" $(average "${BEFORE_LIST[@]}")) AFTER_AVG=$(printf "%.2f\n" $(average "${AFTER_LIST[@]}")) echo "Before average: $BEFORE_AVG" echo "After average: $AFTER_AVG" # Calculate average percent increase, decrease or no change for the list if [ "$BEFORE_AVG" != "0.00" ]; then PERCENT_CHANGE=$(echo "(($AFTER_AVG - $BEFORE_AVG) / $BEFORE_AVG) * 100" | bc -l) if [ "$(echo "$PERCENT_CHANGE > 0" | bc -l)" -eq 1 ]; then printf "Average percent increased: %.2f%%\n" "$PERCENT_CHANGE" elif [ "$(echo "$PERCENT_CHANGE < 0" | bc -l)" -eq 1 ]; then printf "Average percent decreased: %.2f%%\n" "$PERCENT_CHANGE" | tr -d '-' else echo "No change in average." fi else echo "Percent change from before to after: undefined (division by zero)" fiCode language: Bash (bash)It runs like this:
$ average.sh --before=13.07,9.75,16.14,7.71,10.32 --after=1.22,1.28,1.13,1.19,1.26 Before average: 11.40 After average: 1.22 Average percent decreased: 89.30%In this instance, it was calculating seconds–but you need to remember that it only goes to two decimal places, so if you need something finer you’ll need to adjust the code or your inputs.
Happy Slacking!





