r_bash – Telegram
IFS Question

One doubt, I am not very clear about IFS from what I have been reading.

Why does the following happen, if for example I do this:

string=alex:joe:mark && while IFS=":" read -r var1; do echo "${var1}"; done < <(echo "${string}")

why in the output it prints all the value of the string variable (alex:joe:mark) instead of only printing the first field which would be alex depending on the defined IFS which is : ?

On the other hand if I run this:

string=alex:joe:mark && while IFS=":" read -r var1 var2; do echo "${var1}"; done < <(echo "${string}")

That is, simply the same but initializing a second variable with read, and in this case, if I do echo "${var1}" as it says in the command, if it only prints the first field alex.

Could you explain me how IFS works exactly to be able to understand it correctly, the truth is that I have read in several sites about it but it is not clear to me the truth.

Thank you very much in advance

https://redd.it/1cii4kk
@r_bash
Need help doing the bash noscript to generate csv file

So I am trying to get the Data from accounts.csv file. the data looks like this:

id,location_id,name,noscript,email,department
1,1,Susan houston,Director of Services,,
2,1,Christina Gonzalez,Director,,
3,2,Brenda brown,"Director, Second Career Services",,

and I get like this:

id,location_id,name,noscript,email,department
1,1,Susan Houston,Director of `Services,shouston@abc.com`,
2,1,Christina `Gonzalez,Director,cgonzalez@abc.com`,
3,2,Brenda `Brown,"Director,bbrown@abc.com`,

but here is the thing I want that if the generated emails are the same then i should add location_id inside it like if there are two emails like this "shouston@abc.com" then both of them should look like this "shouston<location_id>@abc.com".

here is the noscript:



#!/bin/bash
# Check if the correct number of arguments is provided
if [ "$#" -ne 1 ]; then
echo "Usage: $0 accounts.csv"
exit 1
fi
# Check if the input file exists
if [ ! -r "$1" ]; then
echo "File $1 not found!"
exit 1
fi
# Function to process each line of the input file
function process_line() {
IFS=',' read -r -a fields <<< "$1"
id="${fields[0]}"
location_id="${fields[1]}"
name="${fields[2]}"
position="${fields[3]}"
# Format name: first letter uppercase, rest lowercase
formatted_name=$(echo "$name" | awk '{print toupper(substr($1,1,1)) tolower(substr($1,2)) " " toupper(substr($NF,1,1)) tolower(substr($NF,2))}')
# Format email: lowercase first letter of name, full lowercase surname, followed by u/abc.com
formatted_email=$(echo "$name" | awk '{print tolower(substr($1,1,1)) tolower($NF)}')
formatted_email+="@abc.com"

# Check if the email already exists
if [[ "${emails[@]}" =~ "$formatted_email" ]]; then
# If the email exists, append location_id
formatted_email="${formatted_email%%@*}${location_id}@abc.com"
else
# If the email doesn't exist, add it to the array
emails+=("$formatted_email")
fi

# Output the formatted line
echo "${id},${fields[1]},${formatted_name},${position},${formatted_email},"
}

# Initialize array to store processed emails
declare -a emails
# Copy the header from the input file to accounts_new.csv
head -n 1 "$1" > accounts_new.csv
# Process each line (excluding the header) of the input file and append to accounts_new.csv
tail -n +2 "$1" | while IFS= read -r line || [ -n "$line" ]; do
if [ -n "$line" ]; then
process_line "$line"
fi
done >> accounts_new.csv
echo "Processing completed. Check accounts_new.csv for the updated accounts."
# Ensure the output file exists and is readable
output_file="accounts_new.csv"
if [ -r "$output_file" ]; then
echo "File $output_file created successfully."
else
echo "Error: Failed to create $output_file."
exit 1
fi
the problem is that it checks if the email already exist in the file and it does the job but the first one does not get the location_id. for example if there is 3 emails that are the same only last 2 of them get the location_id inside them and not first one. but i want all of them to have it.

problem might be here and i would appreciate the help:

# Check if the email already exists
if [[ "${emails[@]}" =~ "$formatted_email" ]]; then
# If the email exists, append location_id
formatted_email="${formatted_email%%@*}${location_id}@abc.com"
else
# If the email doesn't exist, add it to the array
emails+=("$formatted_email")
fi

sorry if the explanation or the code quality is bad.

https://redd.it/1cikz89
@r_bash
read variable from a pipe - why doesn't this work?

$ echo one two | read A B && echo A is $A
$ A is
$

https://redd.it/1cioks4
@r_bash
Useful programming language that can replace Bash? Python, Go, etc.

Looking for recommendations for a programming language that can replace bash (i.e. easy to write) for noscripts. It's a loaded question, but I'm wanting to learn a language which is useful for system admin and devops-related stuff. My only "programming" experience is all just shell noscripts for the most part since I started using Linux.

One can only do so much with shell noscripts alone. Can a programming language like Python or Go liberally used to replace shell noscripts? Currently, if I need a noscript I go with POSIX simply because it's the lowest denominator and if i need arrays or anything more fancy I use Bash. I feel like perhaps by nature of being shell noscripts the syntax tends to be cryptic and at least sometimes unintuitive or inconsistent with what you would expect (moreso with POSIX-compliant noscript, of course).

At what point do you use move on from using a bash noscript to e.g. Python/Go? Typically shell noscripts just involve simple logic calling external programs to do the meat of the work. Does performance-aspect typically come into play for the decision to use a non-noscripting language (for the lack of a better term?).

I think people will generally recommend Python because it's versatile and used in many areas of work (I assume it's almost pseudo code for some people) but it's considered "slow" (whatever that means, I'm not a programmer yet) and a PITA with its environments. That's why I'm thinking of Go because it's relatively performant (not like it matters if it can be used to replace shell noscripts but knowing it might be useful for projects where performance is a concern). For at least home system admin use portability isn't a concern.

Any advice and thoughts are much appreciated. It should be evident I don't really know what I'm looking for other than I want to pick up programming and develop into a marketable skill. My current time is spent on learning Linux and I feel like I have wasted enough time with shell noscripts and would like to use tools that are capable of turning into real projects. I'm sure Python, Go, or whatever other recommended language is probably a decent gateway to system admin and devops but I guess I'm looking for a more clear picture of reasonable path and goals to achieve towards self-learning.

Much appreciated.

https://redd.it/1citxqk
@r_bash
rain.sh - Raining in the Linux Terminal

Raining in the Linux Terminal

I have created this noscript because I always play rain sounds while working, and I thought it would be relaxing to have a rain of characters. Feel free to improve and modify the noscript :)

Thank you all, and I hope you enjoy it!

#!/bin/bash

# Display help message
show_help() {
echo "Usage: $0 [density] [character] [color code] [speed]"
echo " density : Set the density of the raindrops (default 3)."
echo " character : Choose the raindrop character (default '/')."
echo " color code : ANSI color code for the raindrop (default 37 for white)."
echo " speed : Choose speed from 1 (slowest) to 5 (fastest)."
echo
echo "Example: $0 5 '@' 32 3"
}

# Function to clear the screen and hide the cursor
initialize_screen() {
clear
tput civis # Hide cursor
height=$(tput lines)
width=$(tput cols)
}

# Declare an associative array to hold the active raindrops
declare -A raindrops

# Function to place a raindrop at a random position
place_raindrop() {
local x=$((RANDOM % width))
local speed=$((RANDOM % (5 - speed_range + 1) + 1)) # Speed adjustments
raindrops[$x]=0,$speed
}

# Function to move raindrops
move_raindrops() {
clear # Always clear the screen for each frame

# Place new raindrops randomly based on specified density
for ((i=0; i<density; i++)); do
place_raindrop
done

# Print the raindrops and update their positions
for x in "${!raindrops[@]}"; do
IFS=, read y speed <<< "${raindrops[$x]}"
tput cup $y $x
echo -en "\e[${color}m${rain_char}\e[0m" # Use specified color and character

# Increment the raindrop down at its speed rate
if ((y + speed < height)); then
raindrops[$x]=$((y + speed)),$speed
else
unset raindrops[$x] # Remove the raindrop if it reaches the bottom
fi
done
}

# Check if help is requested
if [[ "$1" == "-h" || "$1" == "--help" ]]; then
show_help
exit 0
fi

# Initialize the screen
initialize_screen

# Set variables from command-line arguments
density=${1:-3} # Default density is 3
rain_char=${2-'/'} # Correctly defaults to *, handling special characters
color=${3:-'37'} # Default color blue (34)
speed_range=${4:-3} # Default speed range is 3 (1 slowest, 5 fastest)

# Main loop to animate raindrops
trap "cleanup" SIGINT SIGTERM # Properly handle user interruption
while true; do
read -t 0.1 -n 1 key
if [[ $key == "q" ]]; then
break
fi
move_raindrops
done

# Function to reset terminal settings on exit
cleanup() {
tput cnorm # Show cursor
clear
}
trap cleanup EXIT

https://redd.it/1cj3xee
@r_bash
Make dirname -z accept nul-delimited input?

I store an array files containing list of file names that will later be used for further processing (files need to be absolute paths since I reference them elsewhere). For example, I want to determine the minimum amount of mkdir -p arguments to re-create the directories where these files belong.

My files don't have newlines in them but they should still be nul-delimited for good practice. I have the following but the last line doesn't work with error warning: command substitution: ignored null byte in input because I think nul characters can't be in a string:

# Store files in 'files' array
while IFS= read -r -d '' f; do
files+=("$f")
done < <(fd --print0 --base-directory "$rootdir" . "$rootdir" )

# TODO determine minimum amount of directories needed as arguments for mkdir -p
dirname -z "$(printf "%s\0" "${files@}" | sort -zu )" | tr '\0' '\n'


Anyway, a solution is dirname -z -- "${files[@]}" | sort -zu | xargs -0 mkdir -p -- but I'm more curious on the general approach to similar problems with handling nul-delimited items since is is prevalent in noscripting in general:

Is the above with `xargs -0` the go-to simplest noscripting solution whenever you want to pass items that should be nul-delimited as arguments? And that all commands involved should use `-print0`, `-z`, etc. and if an application doesn't support that, you would have to convert it by using something similar to the while loop above? In most of my noscripts, I assumed filenames don't contain newline characters so I never needed to use xargs since most applications assume items are space or newline-delimited. Should xargs dependency be avoided or it's prevalent and useful in general noscripting, something that is used liberally?

What would a (reasonably) Bash (or maybe even POSIX) way to accomplish the same thing?

https://redd.it/1cjdgte
@r_bash
Roman Numerals to Hindi-Arabic Numerals Convertor

### Here is my working attempt at making a roman numerals convertor noscript:

#!/bin/bash
# vim: foldmethod=marker

function romanToArabic {
local input=$1
local result=0
local prevChar=""
local currChar=""
local currValue=0
local prevValue=0

for ((i=0; i<${#input}; i++)); do
currChar="${input:i:1}"

case $currChar in
"I") currValue=1 ;;
"V") currValue=5 ;;
"X") currValue=10 ;;
"L") currValue=50 ;;
"C") currValue=100 ;;
"D") currValue=500 ;;
"M") currValue=1000 ;;
) continue ;;
esac
# Comment{{{
# For numbers such as IV
# The loop first executes the else block
# since there is no prevValue yet.
# so 1 is added to the result variable
# but in the case of IV and such the second iteration
# executes the if block, and so we have to substract 2
# from the result variable. 1 for the incorrect addition
# and 1 for the current number.
# }}}
if ((prevValue < currValue)); then
result=$((result + currValue - 2
prevValue))
else
result=$((result + currValue))
fi

prevChar="$currChar"
prevValue="$currValue"
done

echo "$result"
}

if [ -z "$1" ]; then
echo "Usage: $0 <inputFileorromanNumerals>"
exit 1
fi

if [ -f "$1" ]; then
inputFile="$1"

while IFS= read -r line; do
eval "line=$(echo "$line" | sed -E 's/(IVXLCDM+)/$(romanToArabic "\1")/g')"
echo "$line"
done < "$inputFile" > "$inputFile.tmp"

mv "$inputFile.tmp" "$inputFile"

echo "Roman numerals converted in $inputFile"
else
romanNumerals="$1"
arabicNumber=$(romanToArabic "$romanNumerals")
echo "Roman numerals '$romanNumerals' converted to: $arabicNumber"
fi

https://redd.it/1cje7bw
@r_bash
History for current directory???

I just had an idea of a bash feature that I would like and before I try to figure it out... I was wondering if anyone else has done this.
I want to cd into a dir and be able to hit shift+up arrow to cycle back through the most recent commands that were run in ONLY this dir.
I was thinking about how I would accomplish this by creating a history file in each dir that I run a command in and am about to start working on a function..... BUT I was wondering if someone else has done it or has a better idea.

https://redd.it/1ckm4ud
@r_bash
How to generate a random string using a seed phrase?

I am looking for a way to generate a random string using a seed phrase in the MacOS Terminal.

Ideally, I am looking for a solution that does not require any libraries/packages that need to be installed.

I also want to be able to specify the character set.

Is this possible with Bash?

https://redd.it/1ckx3o2
@r_bash
adding newline to two variables

Hello all,

In the below snippet, I'm trying to combine the output of 2 external output with a new line between the two output.

Desired output:
both:
f1
f2
f3
f4
Current output:
both:
f1
f2f3
f4

#!/bin/bash

mkdir /tmp/dir1 /tmp/dir2
touch /tmp/dir1/f1 /tmp/dir1/f2
touch /tmp/dir2/f3 touch /tmp/dir2/f4

# nl=$(echo "\n")
nl=$(echo)
# nl=$(echo -e "\n")

dir1="$(ls -1 /tmp/dir1)"
dir2="$(ls -1 /tmp/dir2)"
echo dir1:
echo "$dir1"
echo dir2:
echo "$dir2"
#both="$(echo "$dir1$nl$dir2")"
both=$(echo "$dir1$nl$dir2")
#both="${dir1}\n${dir2}"
echo both:
echo "$both"

https://redd.it/1cl0s1h
@r_bash
Wrote my first bash noscript, looking for someone to look it over and make sure I am doing things correctly

I wrote my first bash noscript, a noscript to back up my linux system. I am going to have a systemd timer run the noscript daily and was hoping someone could tell me if I am doing ok.

Thanks
Suzie

#!/usr/bin/bash

######Define noscript variables

backupdest=/mnt/Backups/$(cat /etc/hostname)
filename=$(date +%b-%d-%y)

######Create backup tar archive

if ! -d "$backupdest" ; then
mkdir "$backupdest"
fi

#######Create tar archive

tar -cpzf "$backupdest/$filename" --exclude={\
"/dev/",\
"/proc/
",\
"/sys/",\
"/tmp/
",\
"/run/",\
"/mnt/
",\
"/media/",\
"/lost+found",\
"/usr/lib/
",\
"/usr/share/",\
"/usr/lib/
",\
"/usr/lib32/",\
"/usr/include/
",\
"/home/suzie/.cache/",\
"/home/suzie/.cmake/
",\
"/home/suzie/.config/",\
"/home/suzie/.var/
",\
} /


######Delete previous weeks daily backup

find "$backupdest" -mtime +7 -delete

########Create Weekly folder

if ! -d "$backupdest/weekly" ; then
mkdir "$backupdest/weekly"
fi

########Copy Sundays daily backup file to weekly folder

if $(date +%a) == Sun ; then
cp "$backupdest/$filename" "$backupdest/weekly"
fi

########Delete previous months weekly backups

find "$backupdest/weekly" +31 -delete

########Create monthly folder

if ! -d "$backupdest/monthly" ; then
mkdir "$backupdest/monthly"
fi

########Copy backup file to monthly folder

if $(date +%d) == 1 ; then
cp "$backupdest/$filename" "$backupdest/monthly"
fi

########Delete previous years monthly backups

find "$backupdest/monthly" +365 -delete

https://redd.it/1clexd4
@r_bash
how to get a unique emails?

so in this noscripts there are emails in all_emails variable and i want to get the unique ones. this noscript does not work. any suggestions?

for email in "$allemails"; do
        if [[ "$email" -eq "$all
emails" ]]; then
        echo "$email - not unique"
        else
        echo "$email - unique"
        fi
    done


https://redd.it/1cln8nr
@r_bash
Why my following noscript doesn’t provide any output?


file=()
while read -r -d ''
do
file+=(“$REPLY”)
done < <(find . -print0)

echo “${file[@]}”


https://redd.it/1clrl3g
@r_bash
Bash AWS kungFu migrating AWS Lambda functions from the Go1.x runtime

I have been working on Migrating AWS Lambda functions from the Go1.x runtime to the custom runtime on Amazon Linux 2, Created the sprint noscript to list lambda func in all region

https://github.com/muhammedabdelkader/Micro-Sprint/blob/main/reports/list\_lambda.sh

Don't forgot the filter command

https://redd.it/1cm6g5v
@r_bash
netcat as non root

With the help of this sub, I was able to get my netcat command to run as expected

printf '#011001\015\012' | netcat -N 192.168.x.x 8080

works perfectly....as root

but I need to be able to run it as a non root user. While it will execute, it does not actually do anything. I cannot figure out why

I have even tried via sudo or su and it just will not execute

Any suggestions to get this to work as a regular user?

I see no errors or why it won't send the commands. I am assuming this is for security reasons...

https://redd.it/1cmaqw6
@r_bash
Settings $PS1 Variable (Prompt String)

In Linux, the bash shell allows you to customize the command prompt that appears before each new line in your terminal. This is done using special prompt variables that are expanded by the shell when it displays the prompt. Here are some of the most commonly used prompt variables:

1. \u - The username of the current user.
2. \h - The hostname up to the first dot. For example, if the hostname is "example.com", then "\\h" will expand to just "example".
3. \W - The basename of the current working directory, with $HOME abbreviated with a tilde (\~).
4. \w - The full pathname of the current working directory, with $HOME abbreviated with a tilde (\~).
5. \$ - A dollar sign ($) for regular users or a hash symbol (#) for the root user.
6. \! - The history number of this command.
7. \t - The current time in 24-hour HH:MM:SS format.
8. \T - The current time in 12-hour hh:mm:ss format.
9. \@ - The current time in 12-hour am/pm format.

You can use these variables to create a custom prompt string by enclosing them in curly braces and separating them with escaped spaces (\\ ). For example, the following prompt variable sets the prompt to display the username, hostname, current directory, and a dollar sign:

export PS1="\u@\h \W\$

https://redd.it/1cmbo6o
@r_bash
Add last login time and elapsed time since current login to prompt in Linux

# Customizing Your Bash Prompt

How to calculate the time of the last login and the time elapsed since the active login in Linux? How do we add them to the $PS1 prompt string variable? This video shows how to do these two things by editing the .bashrc file.

Watching video on YT

https://youtu.be/2uG1Pm3i974

https://redd.it/1cmcyk2
@r_bash
when do you use commands with ./ . ?

Hi! sawing videos about grep command I saw a comand ending in .... grep keytofind ./.

I think that ./ isn't used but maybe I am wrong, when do you use that ./

I know the meaning of ./ but I use in command line go there and then put the commands for example ls , so why should I use there ./

star key.star key = all

Thank you and Regards!

edit by wrong interpretation of star key and markdown

https://redd.it/1cmiaac
@r_bash