r_bash – Telegram
bash behavior with nested parentheses?

Is there a (documented) reason why I can use for i in sd[abc]; do … , done and get correct values of sda, sdb, sdc, but I can't use for i in {sd[abc],mmcblk0}; do … , done because I only get sdaabc and mmcblk0, not sda, sdb, sdc and mmcblk0?

https://redd.it/129m660
@r_bash
Script Complete for now

I finally have the noscript i was working on all day yesterday to a point where it works. There is a couple of nuances id like to refine number 1 being 1.) Have the Choice menu pop up after completion of each section. I know its probably an easy fix but....as I seen yesterday nothing is as simple as you think it is. Following is the noscript i have that works.

#!/bin/bash

var1=/home/mib2/WorkTest/SavedData
var3=/home/mib2/WorkTest/Item1_Data/
var4=/home/mib2/WorkTest/Item2_Data/

cat /home/mib2/WorkTest/paths.txt #Prints the 3 paths above form .txt file)

PS3='Choose what you want to do: '
choices=("Make_Directory" "Copy_Item2_Data" "Copy_Item1_Data" "Tar_Data" "Quit")
select item in "${choices[@]}"; do
case $item in

"Make_Directory")
cd $var1
echo "What is the new directory to save data going to be called?"
read var2
mkdir -m 777 $var2
echo ""
echo "Directory has been made"
echo ""
echo "The Contents of $var1 is now: " ; ls -al --color=none $var1
var5=/home/mib2/WorkTest/SavedData/$var2
echo "The new Data Name and its Location is: $var5 "
;;


"Copy_Item2_Data")
# Generate list of files in directory
echo "Please enter a directory path which has the Truth Data contained within: "
ls $var4 | grep 20230331

# Ask user to choose a file
echo "Please choose the Data to copy:"
read file_name

# Copy chosen file to another directory
cp -r "$var4/$file_name" "$var5"
echo "The file has been successfully copied to $var5"
ls -al --color=none $var5
;;

"Copy_Item1_Data")
# Generate list of files in directory
echo "The following directories or files are in the Item1 Data directory:"
ls $var3 | grep 20230331

# Ask user to choose a file
echo "Please choose a file or Directory to copy:"
read file_name2

# Copy chosen file to another directory
cp -r "$var3/$file_name2" "$var5"
echo "The file has been successfully copied to $var5"
ls -al --color=none $var5
;;


"Tar_Data")
# Generate list of files in Saved Data directory
echo "The following directories or files are in the Saved Data directory:"
ls -al /home/mib2/WorkTest/SavedData

# Ask user to choose a file
echo "Please choose a Directory to tar:"
read file_name3

#cd $var1
tar -cvf $var5.tar $var5
chmod 777 $var5.tar
break
;;

"Quit")
echo "User requested exit"
exit
;;
*) echo "invalid option $REPLY";;
esac
done

https://redd.it/129n103
@r_bash
How can i send email with bash noscript/from terminal

Im trying to write a noscript that will send email every day about some information about system. I tried sendmail and curl from terminal but i couldnt send email. Anyone can enlighten me? I am using arch linux.

https://redd.it/129o2mp
@r_bash
how bad of an idea is it to pipe (via named pipe) something into an interactive shell?

I have a noscript, `pipe-reciever.sh` that takes output of a named pipe and pipes it into an interactive shell:

#!/usr/bin/env bash
tail -f test_pipe | bash -i

(tail is used here so that bash doesn't exit after 1 input). Since any process can write to this, is it a huge security hole? if the pipe is in my home directory and a malicious process can write to the pipe, it can execute arbitrary code. Is it any different than if the same malicious process could write arbitrary code to a config file e.g. my .bashrc?


Why am I doing this? (backstory/possible XY problem): I want to trigger some of my bash keybindings programmatically. I've found it's possible by running my pipe-reciever noscript and sending the keys using another noscript like:
`printf $'\cp\ct' > test_pipe`
which will send a `C-p C-t` sequence and the interactive shell will execute the appropriate key binding, which I defined in my .bashrc.

I really do need to trigger these bindings programmatically: I'm using bash's keybinding functionality to supplement an app called [Key Mapper](https://github.com/keymapperorg/KeyMapper) which is no longer being actively developed. I'm using Key Mapper to execute shell noscripts in Termux. These shell noscripts contain variations of the `printf` command from above which trigger my bash keybindings.

https://redd.it/129yc7s
@r_bash
Bash noscript with some steps

So i am trying to write a bash program that will capable with these steps:

1. Every night, program list all belows and send mail to related person.
1. Which users are logged in
2. How was the overall performance of ram, cpu etc
2. When user wants to use rm -rf command, program should ask "you sure" and if user type yes it will be deleted
3. Program need to list all the changes done on environment on a file. When new user logged in it will show 10 changes as a list.

I used debug_trap but couldnt make it work for rm part. I am not sure what i need to list as environment changes and how to detech if new user logged in. Thanks in advance.

https://redd.it/12aczvm
@r_bash
Problem with single quotes

I'm trying to display the following string, without modifying the variable content and keep double and single quotes intact:

noscript="I don't look good when I cry"
/bin/bash -c "printf '$noscript'"

Is possible?

https://redd.it/12aeq1u
@r_bash
How can I ignore first letters when searching with fzf?

I looked up changing the search scheme scoring criteria for fzf but that seemed to be too complicated for the task I want and gave up. I'm also confused if it can be done with -n or --nth options. The -n option works but only for numbered index of letters. Here I want it after specific part not a numbered index. I'm also aware of the --tiebreak=end option which helps, but still I want to completely ignore the first part of fields.

I just want to search the last part of a string.

Example: I want to search the last words of path after the final / only:

 echo -e '/ignore/these/words/here/Search This\n/ignore/these/words/here/Also Here\n/ignore/these/words/here/And These Words' | fzf  


How can I do that without changing the phrases of echo themselves? I want fzf to search what I need to be ignored in those examples.

Thank you in advance for any help

https://redd.it/12ax9j7
@r_bash
Help with renaming set of file

I have few files in a folder

the naming convention is

Mon 20230304 p.1 Matter and Teaching.m4a
Mon 20230304 p.2 Matter and Teaching.m4a
Sun 20230310 p.1 Matter and Music.m4a
Sun 20230310 p.1 Matter and Music.m4a
etc

I'd like to swap the position of the first two strings - so it starts with the date and then gives the day of the week -

2023_03_04 Mon p.1 etc

Any one can suggest a quick way to do it?

https://redd.it/12ay937
@r_bash
I just learned about rlwrap, that can let your read commands be readline enabled with history and filename completion. (Tip)

rlwrap seems like a nice program that lets you use bash's readline extension, for history and filename completion, for programs that reads input from stdin, but doesn't give access to readline.

I think you need some Unix like operating system to leverage upon this "wrapper".

If you run a Unix, or Unix like operating system, then there is a high probability
that it is available in your repository.

There are other options like socat, but rlwrap is specialized for just this task
of enabling readline for programs that doesn't utilize them,, like bash's read command.

I haven't tried it yet, as I have just installed it, but I came by it by reading a manual page
for something else, and it is in the apt repository, so I think it should be all good.

You can read about it here at it's github repo.

https://redd.it/12b0woi
@r_bash
build latest version of curl from source and install to correct directory

Hey, fellow bash enthusiasts. I got into building curl from source to take advantage of more recently added features. As one does, I noscripted it so I can do this programmatically. I'd love some critique on any aspects of the noscript. I have a few specific points too:

- Is it reckless of me to purge the host's installed curl and then try to build from source? Do I need to trap failures so I can re-install curl if it was originally present? (I.e., clean up after a failure?)

- For downloading the source, instead of installing/purging curl, should I just fall back to wget (and other things) if curl isn't initially available for downloading the curl source?

- Is it unreliable to use "which curl" to determine where on the system curl likes to live?

- Do I need more sophisticated error checking around the make/make install steps?

Thanks for taking a look and sharing your feedback. Much appreciated!

_

#!/usr/bin/env bash

# debugging switches
# set -o errexit # abort on nonzero exit status; same as set -e
# set -o nounset # abort on unbound variable; same as set -u
# set -o pipefail # don't hide errors within pipes
# set -o xtrace # show commands being executed; same as set -x
# set -o verbose # verbose mode; same as set -v

source ./functions.sh

die-if-not-root

apt-get -y update && apt-get -y upgrade

TEMP_DIR=$(mktemp --directory)
cd-or-die "${TEMP_DIR}"

if program-not-available curl; then
apt-get -y install curl
fi

die-if-program-not-available curl "An existing \`curl\` isn't available, so the noscript can't determine where to install a new \`curl\`."

# find where curl lives, so we can install new curl using the same directory path prefix
CUR_CURL_PATH=$(which curl)
PREFIX_FOR_MAKE=$(echo "${CUR_CURL_PATH}" | sed "s,/[^/]*$,," | sed "s,/[^/]*$,,")

# get latest stable version of curl
LATEST_VER=$(curl --silent https://curl.se/changes.html | grep --max-count 1 --only-matching --perl-regexp "(?<=<h2> Fixed in ).*?(?= -.*)")
ARCHIVE_BASENAME="curl-${LATEST_VER}"
curl --location --show-error --silent --url "https://curl.se/download/${ARCHIVE_BASENAME}.tar.gz" --output "${TEMP_DIR}/${ARCHIVE_BASENAME}.tar.gz"

# remove existing curl, so we can install a new one
apt-get -y purge curl

if ! tar -xzvf "${ARCHIVE_BASENAME}.tar.gz"; then
die "Couldn't extract source code via \`tar\`."
fi

# install dependencies for build
apt-get -y install libbrotli1 libbrotli-dev
apt-get -y install libssh2-1 libssh2-1-dev
apt-get -y install libzstd1 libzstd-dev

cd-or-die "${ARCHIVE_BASENAME}"

if ! ./configure --enable-websockets --prefix="${PREFIX_FOR_MAKE}" --with-brotli --with-libssh2 --with-nghttp2 --with-ngtcp2 --with-openssl --with-zstd; then
die "\`configure\` failed."
fi

if ! make; then
die "\`make\` failed."
fi

if ! make install; then
die "\`make install\` failed."
fi

die-if-program-not-available curl "Building \`curl\` seemed to work, but \`curl\` can't be located."



I utilize some helper functions of mine in another noscript. Here they are, if someone wants to see them:


#!/usr/bin/env bash

# usage: die "$MESSAGE"
die() {
printf >&2 "\n*\n* Error: %s\n* This error is unrecoverable. Check above for additional error messages.\n*\n\n" "${1:-Unspecified error.}"
exit 1
}

# usage: am-root
# returns 0 if root, 1 if not root
am-root() {
if ((${EUID:-$(id -u)} != 0)); then
return 1
else
return 0
fi
}

# usage: die-if-not-root
die-if-not-root() {
if ! am-root; then
die "Please run this noscript as root (e.g., using ‘sudo’)."
exit 1
fi
}

# usage: die-if-root
die-if-root() {
if am-root; then
die "Please run
this noscript as a non-root user (e.g., not as root, not using ‘sudo’)."
exit 1
fi
}

# usage: die-if-program-not-available $PROGRAM_NAME "$MESSAGE"
die-if-program-not-available() {
program-not-available "${1}" && die "${2}"
}

# usage: program-not-available $PROGRAM_NAME
# returns 0 if program isn't available, 1 if program is available
program-not-available() {
program-available "${1}" && return 1
return 0
}

# usage: program-available $PROGRAM_NAME
# returns 0 if program is available, 1 if program isn't available
program-available() {
command -v "${1}" >/dev/null 2>&1 && return 0
return 1
}

# usage: die-if-file-not-present $FILENAME_WITH_PATH "$MESSAGE"
die-if-file-not-present() {
[ ! -f "${1}" ] && die "${2}"
}

# usage: cd-or-die $DIRECTORY "$MESSAGE"
cd-or-die() {
cd "${1}" || die "Couldn't cd to ${1}."
}

https://redd.it/12b944i
@r_bash
Problems with sudo and single quote.

I executed the following command in interactive bash, but output from echo contains string '-e'.

```shell

sudo -u root sh -c 'for name in raw mangle nat filter; do echo -e "#######$name#######\\n"; iptables -t $name -nvL; done'

```

https://redd.it/12bfhw6
@r_bash
Progress bar showing the progress of a data migration between two different RDBMS?

One of the most amazing features I've ever seen in Linux terminals is that progress bar showing the going of a certain package installation, for example.

I'd like to make the same but to show the progress of a data migration between two different databases. I have a table (let's call it "followup") that records the process of the migration through a status, that is, if a table in the destiny database has been filled with all the data from the source, its status in the followup is put as "ok". It's also known the total amount of tables that is to be migrated. Thus, the relation between "the amount of tables migrated" and "the total amount to be migrated" is known.

An important point here: I have a main shell noscript that executes the SQL migration file inside it. Therefore, when the latter is executed, my shell noscript gets stuck in that specific line. One thing I've been struggling with is that when the SQL migration file is being executed, my shell noscript can't be executed in parallel to track the progress of the migration.

The following code just shows how I'm executing the SQL noscript inside my shell noscript. The nohup command is used as a way of avoiding the migration itself to stop because of network issues or stuff like that.

nohup sqlplus -s / as sysdba <<< @./noscript.sql > /tmp/log.out 2>&1

How could I make a progress bar showing the progress of this migration through a shell noscript (we're talking about bash in this case)? I showed the whole scenario to clear my intentions, but I think that knowing the relation explained before and how to execute this SQL noscript in parallel with a progress bar record might be enough to solve the problem.

Is it even reachable? I appreciate any help, thoughts, ideas, etc.

https://redd.it/12bgyeb
@r_bash
timeout vs gtimeout? (MacOS)

I am cleaning up a Makefile, and see this line:

TIMEOUT := $(shell command -v timeout || command -v gtimeout)


AFAIK gtimeout is needed for MacOS.

Is this really needed for MacOS?

I can't test it, I only use Linux.

https://redd.it/12bf462
@r_bash
How can i have this ignore files that are already gzipped?

I am working on a noscript and I want to ignore already gzipped files so that it is not trying to zip them again. What would be the best way to do so?

for LOG in $(find "${ARCHIVE}/${COMPONENT_TYPE}" -type f -mtime +"${AGE_TO_ZIP}"); do
gzip "${LOG}" -S .$(date -I).gz
done


Edit: Thanks for the help. Solution was to add ! -name \\\*.gz after my age variable

https://redd.it/12bjgq0
@r_bash
GPT quality check

I'm not very good at bash noscripting so I asked chatgpt solve a problem for me. I want to ask if any string in one array also exists in the other array. It gave me a result and it works, my question here is if it is a good way of doing it?

this noscript won't be running on huge datasets so this is for my curiosity.

#!/bin/bash

# define the first array
array1=("apple" "banana" "orange" "pear" "peach")

# define the second array
array2=("banana" "grape" "peach" "watermelon")

# loop through each element in array1
for item in "${array1@}" do
# check if the item is in array2
if [ " ${array2[*} " == " $item " ]]
then
echo "$item is in array2"
else
echo "$item is not in array2"
fi
done

https://redd.it/12biwvc
@r_bash
To provide an exit 1 status and also allow the noscript to continue running

Hello all,

I want to check if it is possible to add an exit 1 statement if $comparison_delta1 and/or $comparison_delta2 is not empty and then also allow the noscript to finish? The idea is that, I want to deploy my noscript to Jenkins, mark my Jenkins build failed when comparison_delta* exist and the output of it. I can go through my failed Jenkins jobs to find out the servers that aren't supposed to be pinging on my subnets.

&#x200B;

Here is part of my noscript. This part is to compare the ping results of the subnets to the master/gold copy (known IP addresses). Once the comparison function is completed, the noscript will be finishing with cleaning up old ping/comparison files. Thank you all in advance.

&#x200B;

\# Comparing ping result of 192.28.x.x subnet against gold copy

cat $output_file1|awk -F. {'print $1'}|while read host; do egrep -w $host $mastercopy1 >/dev/null||echo $host "${BOLD}${RED}is NOT my server!${RESET}" >> $comparison_delta1

done

echo "See result for 192.28.x.x subnet"

if [ -s "$comparison_delta1" \]

then

cat $comparison_delta1

else

echo -e "${BOLD}${GREEN}Subnet only known IP pinging!${RESET}"

fi

\# Comparing ping result of 192.27.x.x subnet against gold copy

cat $output_file2|awk -F. {'print $1'}|while read host; do egrep -w $host $mastercopy2 >/dev/null||echo -e $host "${BOLD}${RED}is NOT my server!${RESET}" >> $comparison_delta2

done

echo "See result for 192.27.x.x subnet"

if [ -s "$comparison_delta2" \]

then

cat $comparison_delta2

else

echo -e "${BOLD}${GREEN}Subnet only have known IP pinging!${RESET}"

fi

\##Cleaning up old logs

find /tmp/ \\( -name 'PingResults*' -o -name 'Non-Known_IP*' \\) -mmin +1 -exec rm -f {} \\;

https://redd.it/12bpna0
@r_bash
Here document detail - poorly written docs?

According to the Bash docs:

> This type of redirection instructs the shell to read input from the current source until a line containing only word (with no trailing blanks) is seen.

Since it explicitly called out no trailing blanks, I read that as allowing leading blanks but that does not seem to work. I'm just curious if other people agree with my reading and think the docs would be clearer it they read with no leading or trailing blanks or would this be clear if only I understood X (in which case, what is that X).

https://redd.it/12bog6k
@r_bash
Get all arguments between named arguments

I want to run a function such as
foo -e 1 2 3 -f 4 

so it recognizes 1 2 3 as arguments to be appended to -e case in the switch-like statement i have at present:
foo() {
exclude=()
while test $# -gt 0; do
case $1 in
-e) exclude+=$2; shift 2;;
*) break;;
esac
done

testlist=(1 2 3 4)
for e in ${exclude[@]}; do
testlist=(${testlist[@]/$e/})
done

echo ${testlist[@]}
}

The -f is just a dummy to serve as example for elements to stop being appended to -e case.

Any ideas on how to do this?

https://redd.it/12brmia
@r_bash
Is there a recommended alternative to getopts?

Hi everyone, I’m a beginner in Bash noscripting and I need some advice on how to parse options.

I know there are two common ways to do it:

Writing a custom "while loop" in Bash, but this can get complicated if you want to handle short-form flags that can be grouped together (so that it detects that “-a -b -c” is the same as “-abc”)
Using getopts, but this doesn’t support long-form options (like “–help”)

I’m looking for a solution that can handle both short-form grouping and long-form, like most noscripting languages and the Fish shell have (argparse). Is there a recommended alternative to getopts that can do this?

Thanks!

https://redd.it/12bqmyi
@r_bash