r_bash – Telegram
Mass renaming and moving of files according to file structure?

Hi,

I have a bunch of videos organised like this:

Videos
> Friends
> Season 1
> ep1.mp4
> ep2.mp4
> ep3.mp4
> Season 2
> ep1.mp4
> ep2.mp4
> ep3.mp4
> Season 3
> ep1.mp4
> ep2.mp4
> ep3.mp4

Now I want all files renamed according to file structure and moved to parent directory, like this:

Videos
> Friends_Season_1_ep1.mp4
Friends_Season_1_ep2.mp4
Friends_Season_1_ep3.mp4
Friends_Season_2_ep1.mp4
Friends_Season_2_ep2.mp4
Friends_Season_2_ep3.mp4
Friends_Season_3_ep1.mp4
Friends_Season_3_ep2.mp4
Friends_Season_3_ep3.mp4

How can I do that?

Thanks.

https://redd.it/1kc9g9p
@r_bash
How to make false && false fail in Bash Strict Mode?

How to make false && false fail in Bash Strict Mode?

Example:

#!/usr/bin/env bash
# Bash Strict Mode: https://github.com/guettli/bash-strict-mode
trap 'echo -e "\n🤷 🚨 🔥 Warning: A command has failed. Exiting the noscript. Line was ($0:$LINENO): $(sed -n "${LINENO}p" "$0" 2>/dev/null || true) 🔥 🚨 🤷 "; exit 3' ERR
set -Eeuo pipefail

false && false

echo foo



https://redd.it/1kcweni
@r_bash
text variable manipulation without external commands

I wish to do the following within bash, no external programs.

I have a shell variable which FYI contains a snooker frame score. It looks like the 20 samples below. Let's call the shell variable score. It's a scalar variable.

13-67(63) 7-68(68) 80-1 10-89(85) 0-73(73) 3-99(63) 97(52)-22 113(113)-24 59(59)-60(60) 0-67(57) 1-97(97) 120(52,56)-27 108(54)-0 130(129)-4 128(87)-0 44-71(70) 87(81)-44 72(72)-0 0-130(52,56) 90(66)-12

So we have the 2 players score separated by a "-". On each side of the - is possibly 1 or 2 numbers (separated by comma) in brackets "()". None of the numbers are more than 3 digits. (snooker fans will know anything over 147 would be unusual).

From that scalar score, I want six numbers, which are:


1: player1 score

2: player2 score

3: first number is brackets for p1

4: second number in brackets for p1

5: first number is brackets for p2

6: second number in brackets for p2

If the number does not exist, set it to -1.


So to pick some samples from above:

"13-67(63)" --> 13,67,-1,-1,63,-1

"120(52,56)-27" --> 120,27,52,56,-1,-1

"80-1" --> 80,1,-1,-1,-1,-1

"59(59)-60(60)" --> 59,60,59,-1,60,-1

...


I can do this with combination of echo, cut, grep -o "some-regexes", .. but as I need do it for 000s of values, thats too slow, would prefer just to do in bash if possible.

https://redd.it/1kcyrna
@r_bash
What to teach in awk under 4 hours for Undergraduate Computer Science students?
https://redd.it/1kd2nti
@r_bash
find; not specificName AND .png

i want a random file that is not currentPaper and is a png. thsi does not work: what wrong?
selectionPaper=$(find "$selectionPath" . \( ! -name "$currentPaper" -a -name *.png \) | shuf -n 1)



https://redd.it/1kd730b
@r_bash
A command in my noscript does not run.

#!/bin/bash

for i in "$@"; do
case $i in
-W | --Wallpaper )
WALLPAPER="$2"
Hyprland & # Start Hyprland.
sleep 30s && # A Time-Delay to let Hyprland initialize.
alacritty --hold -e set-wal -w "$WALLPAPER" -c -n # Set Sysytem Theme and Wallpaper (Using "swww img" and "wal -i").
shift # Past argument with no value.
;;
-wh | --wlan-home )
WNet-Config -wh # Connect to the network.
shift # Past argument with no value.
;;
-wm | --wireless-mobile )
WNet-Config -wm # Connect to mobile hot-spot.
shift # Past argument with no value.
;;
-* | --* )
echo "Unrecognized argument ( $i )."
exit 1
;;
*)
;;
esac
shift
done

# Why would the alacritty --hold -e <noscript123> not work?

# (I don't use a login manager so maybe it has something to do with the fact it does not find a graphical interface even after Hyprland has started, somebody help please).

#



#



#



#

https://redd.it/1kefknv
@r_bash
What's your favorite non-obvious Bash built-in or feature that more people don't use?

For me, it’s trap. I feel like most people ignore it. Curious what underrated gems others are using?

https://redd.it/1kf5exc
@r_bash
Scriptting exam.

Hi everyone,

Hey everyone, I have an exam coming mid June in OS. I'm pretty bad in Bash and I have the feeling I am going to fail that exam if I try to do it by myself.

You could argue with me to study, but I am a night student, so basically I go to Uni after work. I have a family and honestly sometimes 0 minutes to study. If I have the time, I rather study a subject with more credit points.

Regardless the teacher is super cool and basically allow us to go online for the exam. We have full access to Internet, to chat or to whatever it is. So I was wondering if you guys have an idea how I could pass this exam. I was thinking about GPT or something like that.

The exam will be centered around noscripting. The teacher also said to us in advance that GPT is OK no problem with that but if he sees two identical noscripts, he's going to fail the two student. Like I said he's super cool, so we have access to all the tools online and I was wondering guys if you have any advice.

https://redd.it/1kf6t89
@r_bash
Advice/ Brainstorm for my exam.

Hi everyone,

Hey everyone, I have an exam coming mid June in OS. I'm pretty bad in Bash and I have the feeling I am going to fail that exam if I try to do it by myself.

You could argue with me to study, but I am a night student, so basically I go to Uni after work. I have a family and honestly sometimes 0 minutes to study. If I have the time, I rather study a subject with more credit points.

Regardless the teacher is super cool and basically allow us to go online for the exam. We have full access to Internet, to chat or to whatever it is. So I was wondering if you guys have an idea how I could pass this exam. I was thinking about GPT or something like that.

The exam will be centered around noscripting. The teacher also said to us in advance that GPT is OK no problem with that but if he sees two identical noscripts, he's going to fail the two student. Like I said he's super cool, so we have access to all the tools online and I was wondering guys if you have any advice.

https://redd.it/1kf6n40
@r_bash
Converting Bat to Bash

I am wanting to convert a bat noscript into bash and I want to ensure this is right.

If someone could review the changes and let me know if this is proper that would be absolutely amazing.

Commenting Below the Original code then Converted code

----------------------------------------------

@echo off
noscript COS Regional Flasher
echo.**********************************************************************
echo.
echo. Oneplus 13 - COS Regional Flasher
echo. Originally two noscripts by FTH PHONE 1902 and Venkay
echo. modified by docnok63 and Jonas Salo
echo.
@echo off

cd %~dp0
set fastboot=Platform-Tools\fastboot.exe
if not exist "%fastboot%" echo "%fastboot%" not found. & pause & exit /B 1
set file=vendor_boot
echo.************************ START FLASH ************************
%fastboot% --set-active=a

:: Flash the fastboot images first
%fastboot% flash boot COS_FILES_HERE\boot.img
%fastboot% flash dtbo COS_FILES_HERE\dtbo.img
%fastboot% flash init_boot COS_FILES_HERE\init_boot.img
%fastboot% flash modem COS_FILES_HERE\modem.img
%fastboot% flash recovery COS_FILES_HERE\recovery.img
%fastboot% flash vbmeta COS_FILES_HERE\vbmeta.img
%fastboot% flash vbmeta_system COS_FILES_HERE\vbmeta_system.img
%fastboot% flash vbmeta_vendor COS_FILES_HERE\vbmeta_vendor.img
%fastboot% flash vendor_boot COS_FILES_HERE\vendor_boot.img

:: Check if super.img exists
if exist "super.img" (
%fastboot% flash super super.img
) else (
echo super.img not found. Skipping super.img...
)

:: Reboot to fastbootd
%fastboot% reboot fastboot
echo. ******************* REBOOTING TO FASTBOOTD *******************
ECHO #################################
ECHO # Hit English on Phone #
ECHO #################################
pause

:: Excluded files list (these should not be flashed again)
set excluded_images=boot.img dtbo.img init_boot.img modem.img recovery.img vbmeta.img vbmeta_system.img vbmeta_vendor.img vendor_boot.img my_bigball.img my_carrier.img my_company.img my_engineering.img my_heytap.img my_manifest.img my_preload.img my_product.img my_region.img my_stock.img odm.img product.img system.img system_dlkm.img system_ext.img vendor.img vendor_dlkm.img

:: Loop through all .img files in COS_FILES_HERE but skip excluded images
for %%G in (COS_FILES_HERE\*.img) do (
echo %excluded_images% | findstr /i /c:"%%~nxG" >nul
if errorlevel 1 (
echo Flashing %%~nG...
%fastboot% flash --slot=all "%%~nG" "%%G"
)
)

:: Define partitions list outside the IF block
set "partitions=my_bigball my_carrier my_engineering my_heytap my_manifest my_product my_region my_stock odm product system system_dlkm system_ext vendor vendor_dlkm my_company my_preload"

:: Check if super.img exists, if not, delete, create & flash logical partitions
if not exist "super.img" (
for %%P in (%partitions%) do (
%fastboot% delete-logical-partition %%P_a
%fastboot% delete-logical-partition %%P_b
%fastboot% delete-logical-partition %%P_a-cow
%fastboot% delete-logical-partition %%P_b-cow
%fastboot% create-logical-partition %%P_a 1
%fastboot% create-logical-partition %%P_b 1
%fastboot% flash %%P COS_FILES_HERE\%%P.img
)
) else (
echo super.img found. Logical partition flashes skipped...
)

echo.********************** CHECK ABOVE FOR ERRORS **************************
echo.************** IF ERRORS, DO NOT BOOT INTO SYSTEM **********************

:: Ask if user wants full Chinese bloat or not
choice /C YN /M "Do you want full chinese bloat?:"

if errorlevel 2 (
echo ****************** FLASHING OOS .305 my_preload ******************
%fastboot% delete-logical-partition my_preload_a
%fastboot% delete-logical-partition my_preload_b
%fastboot% delete-logical-partition my_preload_a-cow
%fastboot% delete-logical-partition my_preload_b-cow
%fastboot% create-logical-partition my_preload_a 1
%fastboot% create-logical-partition my_preload_b 1
%fastboot% flash my_preload
OOS_FILES_HERE\my_preload.img
echo ********* Debloat image flashed, Hit any key to continue *********
pause
) else (
echo ********************* CHINESE BLOAT ALREADY FLASHED **************************
echo ********* Keeping bloated my_preload, Hit any key to continue *********
pause
)

:: If super.img was not flashed, exit here but keep window open
if not exist "super.img" (
choice /C YN /M "Do you want to wipe data?:"

if errorlevel 2 (
echo *********************** NO NEED TO WIPE DATA ****************************
echo ***** Flashing complete. Hit any key to reboot the phone to Android *****
pause
%fastboot% reboot
exit /B 0
)

if errorlevel 1 (
echo ****************** FLASHING COMPLETE *****************
echo Wipe data by tapping Format Data on the screen, enter the code, and press format data.
echo Phone will automatically reboot into Android after wipe is done.
pause
exit /B 0
)
)

:: Ask if flashing from ColorOS (press Y for yes or N for no)
echo Are you flashing from ColorOS or Want to WIPE DATA?? (y/n)
choice /c YN /n > nul

:: Check if the user pressed 'y' or 'n'
if errorlevel 2 (
echo *********************** NO NEED TO WIPE DATA ****************************
echo ***** Flashing complete. Hit any key to reboot the phone to Android *****
pause
%fastboot% reboot
) else if errorlevel 1 (
echo ****************** FLASHING COMPLETE *****************
echo Wipe data by tapping Format Data on the screen, enter the code, and press format data.
echo Phone will automatically reboot into Android after wipe is done.
)

pause
----------------------------------------------

----------------------------------------------
Converted code
----------------------------------------------

----------------------------------------------
#!/bin/bash

# Set noscript (not directly equivalent in bash, but can be simulated)
echo "COS Regional Flasher"

echo "**********************************************************************"
echo ""
echo " Oneplus 13 - COS Regional Flasher "
echo " Originally two noscripts by FTH PHONE 1902 and Venkay"
echo " modified by docnok63 and Jonas Salo"
echo ""

# Get the directory of the noscript
SCRIPT_DIR=$(dirname "$0")

# Set fastboot path
FASTBOOT="$SCRIPT_DIR/Platform-Tools/fastboot"

# Check if fastboot exists
if [ ! -x "$FASTBOOT" ]; then
echo "Error: $FASTBOOT not found."
exit 1
fi

# Set file (not used in the original noscript, so keeping it as a variable)
FILE="vendor_boot"

echo "************************ START FLASH ************************"

# Flash the fastboot images first
$FASTBOOT --set-active=a

$FASTBOOT flash boot COS_FILES_HERE/boot.img
$FASTBOOT flash dtbo COS_FILES_HERE/dtbo.img
$FASTBOOT flash init_boot COS_FILES_HERE/init_boot.img
$FASTBOOT flash modem COS_FILES_HERE/modem.img
$FASTBOOT flash recovery COS_FILES_HERE/recovery.img
$FASTBOOT flash vbmeta COS_FILES_HERE/vbmeta.img
$FASTBOOT flash vbmeta_system COS_FILES_HERE/vbmeta_system.img
$FASTBOOT flash vbmeta_vendor COS_FILES_HERE/vbmeta_vendor.img
$FASTBOOT flash vendor_boot COS_FILES_HERE/vendor_boot.img

# Check if super.img exists
if [ -f "super.img" ]; then
$FASTBOOT flash super super.img
else
echo "super.img not found. Skipping super.img..."
fi

# Reboot to fastbootd
$FASTBOOT reboot fastboot
echo " ******************* REBOOTING TO FASTBOOTD *******************"
echo "#################################"
echo "# Hit English on Phone #"
echo "#################################"

read -p "Press Enter to continue..."

# Excluded files list
EXCLUDED_IMAGES="boot.img dtbo.img init_boot.img modem.img recovery.img vbmeta.img vbmeta_system.img vbmeta_vendor.img vendor_boot.img my_bigball.img my_carrier.img my_company.img my_engineering.img my_heytap.img my_manifest.img my_preload.img my_product.img my_region.img my_stock.img odm.img product.img system.img system_dlkm.img system_ext.img vendor.img
vendor_dlkm.img"

# Loop through all .img files in COS_FILES_HERE but skip excluded images
for IMG in COS_FILES_HERE/*.img; do
IMG_NAME=$(basename "$IMG")
if ! echo "$EXCLUDED_IMAGES" | grep -iq "$IMG_NAME"; then
echo "Flashing $IMG_NAME..."
$FASTBOOT flash --slot=all "$IMG_NAME" "$IMG"
fi
done

# Define partitions list outside the IF block
PARTITIONS="my_bigball my_carrier my_engineering my_heytap my_manifest my_product my_region my_stock odm product system system_dlkm system_ext vendor vendor_dlkm my_company my_preload"

# Check if super.img exists, if not, delete, create & flash logical partitions
if [ ! -f "super.img" ]; then
for P in $PARTITIONS; do
$FASTBOOT delete-logical-partition "$P"_a
$FASTBOOT delete-logical-partition "$P"_b
$FASTBOOT delete-logical-partition "$P"_a-cow
$FASTBOOT delete-logical-partition "$P"_b-cow
$FASTBOOT create-logical-partition "$P"_a 1
$FASTBOOT create-logical-partition "$P"_b 1
$FASTBOOT flash "$P" COS_FILES_HERE/"$P".img
done
else
echo "super.img found. Logical partition flashes skipped..."
fi

echo "********************** CHECK ABOVE FOR ERRORS **************************
echo "************** IF ERRORS, DO NOT BOOT INTO SYSTEM **********************"

# Ask if user wants full Chinese bloat or not
read -p "Do you want full chinese bloat? (y/n): " CHOICE
CHOICE=$(echo "$CHOICE" | tr '[:upper:]' '[:lower:]')

if [ "$CHOICE" = "y" ]; then
echo "***************** FLASHING OOS .305 my_preload ******************"
$FASTBOOT delete-logical-partition my_preload_a
$FASTBOOT delete-logical-partition my_preload_b
$FASTBOOT delete-logical-partition my_preload_a-cow
$FASTBOOT delete-logical-partition my_preload_b-cow
$FASTBOOT create-logical-partition my_preload_a 1
$FASTBOOT create-logical-partition my_preload_b 1
$FASTBOOT flash my_preload OOS_FILES_HERE/my_preload.img
echo "******** Debloat image flashed, Hit any key to continue *********"
read -p ""
else
echo "******************** CHINESE BLOAT ALREADY FLASHED **************************"
echo "******** Keeping bloated my_preload, Hit any key to continue *********"
read -p ""
fi

# If super.img was not flashed, exit here but keep window open
if [ ! -f "super.img" ]; then
read -p "Do you want to wipe data? (y/n): " CHOICE
CHOICE=$(echo "$CHOICE" | tr '[:upper:]' '[:lower:]')

if [ "$CHOICE" = "y" ]; then
echo "*********************** NO NEED TO WIPE DATA ****************************"
echo "***** Flashing complete. Hit any key to reboot the phone to Android *****"
read -p ""
$FASTBOOT reboot
exit 0
elif [ "$CHOICE" = "n" ]; then
echo "***************** FLASHING COMPLETE *****************"
echo "Wipe data by tapping Format Data on the screen, enter the code, and press format data."
echo "Phone will automatically reboot into Android after wipe is done."
read -p ""
exit 0
fi
fi

# Ask if flashing from ColorOS (press Y for yes or N for no)
read -p "Are you flashing from ColorOS or Want to WIPE DATA?? (y/n): " CHOICE
CHOICE=$(echo "$CHOICE" | tr '[:upper:]' '[:lower:]')

# Check if the user pressed 'y' or 'n'
if [ "$CHOICE" = "y" ]; then
echo "*********************** NO NEED TO WIPE DATA ****************************"
echo "***** Flashing complete. Hit any key to reboot the phone to Android *****"
read -p ""
$FASTBOOT reboot
elif [ "$CHOICE" = "n" ]; then
echo "***************** FLASHING COMPLETE *****************"
echo "Wipe data by tapping Format Data on the screen, enter the code, and press format data."
echo "Phone will automatically reboot into Android after wipe is done."
fi

read -p "Press Enter to exit..."
----------------------------------------------

https://redd.it/1kg5ege
@r_bash
Can someone help whipping up a quick, compact oneliner to diff / compare config files with old versions after updates?

I want to see the changes from the old to the new config files on Debian (ucf-*, dpkg-new) or Arch (original name vs pacnew).

If I take Debian, I can easily find the files to compare with with ` sudo find /etc/ \( -name '*.dpkg-*' -o -name '*.ucf-*' \)`. So far, so good. On Arch, it wouldn't be much different with pacnew files. The file to compare them with (with `diff -uN`) would be the find result minus the file extension (everything after the last dot).

Somehow, I can't get this to work in a compact oneliner. Can someone help me out here? I don't want to write a multiline noscript with variables, just a quick oneliner.

https://redd.it/1kgsyyl
@r_bash
Stupid Associative Array tricks

The Associative Array in Bash can be used to tag a variable and its core value with any amount of additional information. An associative array is created with the declare built-in by the -A argument:

$ declare -A ASSOCARRAY
$ declare -p ASSOC
ARRAY
declare -A ASSOCARRAY=()

While ordinary variables can be promoted to Indexed Arrays by assignment to the variable using array notation, attempts to do so to create an associative array fail by only promoting to a indexed array and setting element zero(0).

$ declare VAR=value
$ declare -p VAR
declare -- VAR=value
$ VAR[member]=issue
$ declare -p VAR
declare -a VAR=([0]=issue)

This is due to the index of the array notation being interpretted in an arithmetic context in which all non-numeric objects become the numeric value zero(0), resulting in

$ VAR[member]=issue

being semanticly identical to

$ VAR[0]=issue

and promoting the variable VAR to an indexed array.

There are no other means, besides the -A argument to declare, to create an associative array. They cannot be created by assigning to a non-existent variable name.

Once an associative array variable exists, it can be assigned to and referenced just as any other array variable with the added ability to assign to arbitrary strings as "indices".

$ declare -A VAR
$ declare -p VAR
declare -A VAR
$ VAR=value
$ declare -p VAR
declare -A VAR=([0]="value" )
$ VAR[1]=one
$ VAR[string]=something
$ declare -p VAR
declare -A VAR=([string]="something" [1]="one" [0]="value" )

They can be the subject of a naked reference:

$ echo
$VAR
value

or with an array reference

$ echo ${VAR[1]}
one

An application of this could be creating a URL variable for a remote resource and tagging it with the checksums of that resource once it is retrieved.

$ declare -A WORDS=
https://gist.githubusercontent.com/wchargin/8927565/raw/d9783627c731268fb2935a731a618aa8e95cf465/words
$ WORDS[crc32]=6534cce8
$ WORDS[md5]=722a8ad72b48c26a0f71a2e1b79f33fd
$ WORDS[sha256]=1ec8230beef2a7c955742b089fc3cea2833866cf5482bf018d7c4124eef104bd
$ declare -p WORDS
declare -A WORDS=([0]="
https://gist.githubusercontent.com/wchargin/8927565/raw/d9783627c731268fb2935a731a618aa8e95cf465/words" [crc32]="6534cce8" [md5]="722a8ad72b48c26a0f71a2e1b79f33fd" [sha256]="1ec8230beef2a7c955742b089fc3cea2833866cf5482bf018d7c4124eef104bd" )

The root value of the variable, the zero(0) index, can still be referenced normally

$ wget
$WORDS

and it will behave only as the zeroth index value. Later, however, it can be referenced with the various checksums to check the integrity of the retrieved file.

$ [[ "$(crc32 words)" == "${WORDS[crc32]}" ]] || echo 'crc32 failed'
$ [[ "$(md5sum words | cut -f 1)" == "${WORDS[md5]}" ]] || echo 'md5 failed'
$ [[ "$(sha256sum words | cut -f 1 -d ' ')" == "${WORDS[sha256]}" ]] || echo 'sha5 failed'

If none of the failure messages were printed, each of the programs regenerated the same checksum as that which was stored along with the URL in the Bash associative array variable WORDS.

We can prove it by corrupting one and trying again.

$ WORDS[md5]='corrupted'
$ [[ "$(md5sum words | cut -f 1)" == "${WORDS[md5]}" ]] || echo 'md5 failed'
md5 failed

The value of the md5 member no longer matches what the md5sum program generates.

The associative array variable used in the above manner can be used with all of the usual associative array dereference mechanisms. For instance, getting the list of all of the keys and filtering out the root member effectively retrieves a list of all of the hashing algorithms with which the resource has been tagged.

$ echo ${!WORDS[@]} | sed -E 's/(^| )0( |$)/ /'
crc32 md5 sha256

This list could now be used with a looping function to dynamicly allow any hashing program to be used.

verify
hashes () {
local -i retval=0
local -n var="${1}"
local file="${2}"

for hash in $(sed -E 's/(^| )0(
|$)/ /' <<< "${!var@}"); do
prog=''

if which ${hash} &>/dev/null; then
prog="${hash}"
elif which ${hash}sum &>/dev/null; then
prog="${hash}sum"
else
printf 'Hash type %s not supported.\n' "${hash}" >&2
fi

[ -n "${prog}" ] \
&& [ "$(${prog} "${file}" | cut -f 1 -d ' ')" != "${var[${hash}}" ]] \
&& printf '%s failed!\n' "${hash}" >&2 \
&& retval=1
done

return $retval
}
$ verifyhashes WORDS words
$ echo $?
0

This function uses the relatively new Bash syntax of the named reference (`local -n`). This allows me to pass in the name of the variable the function is to operate with, but inside the function, I have access to it via a single variable named "var", and `var` retains all of the traits of its named parent variable, because it effectively is the named variable.

This function is complicated by the fact that some programs add the suffix "-sum" to the name of their algorithm, and some don't. And some output their hash followed by white space followed by the file name, and some don't. This mechanism handles both cases. Any hashing algorithm which follows the pattern of <algo> or <algo>sum for the name of their generation program, takes the name of the file on which to operate, and which produces a single line of output which starts with the resultant hash can be used with the above design pattern.

With nothing output, all hashes passed and the return value was zero. Let's add a nonsense hash type.

$ WORDS[hash]=browns
$ verify
hashes WORDS words
Hash type hash not supported.
$ echo $?
0

When the key 'hash' is encountered for which no program named 'hash' or 'hashsum' can be found in the environment, the error message is sent to stderr, but it does not result in a failure return value. However, if we corrupt a valid hash type:

$ WORDSmd5=corrupted
$ verifyhashes WORDS words
md5 failed!
$ echo $?
1

When a given hash fails, a message is sent to stderr, and the return value is non-zero.

This technique can also be used to create something akin to a structure in the C language. Conceptually, if we had a C struct like:

struct person
{
char * first
name;
char middleinitial;
char * last
name;
uint8t age;
char * phone
number;
};

We could create a variable of that type and initialize it like so:

struct person owner = { "John", 'Q', "Public", 25, "123-456-7890" };

Or, using the designated initializer syntax:

struct person owner = {
.firstname = "John",
.middle
initial = 'Q',
.lastname = "Public",
.age = 25,
.phone
number = "123-456-7890"
};

In Bash, we can just use the associative array initializer to achieve much the same convenience.

declare -A owner=(
first_name="John"
middle_initial='Q'
last_name="Public"
age=25
phone_number="123-456-7890"
)

Of course, we also have all of the usual Bash syntactic restrictions. No commas. No space around the equals sign. Have to use array index notation, not struct member notation, but the effect is the same, all of the data is packaged together as a single unit.

$ declare -p owner
declare -A owner=(middle_initial="Q" last_name="Public" first_name="John" phone_number="123-456-7890" age="25" )
$ echo "${ownerfirst_name}'s phone number is ${ownerphone_number}."
John's phone number is 123-456-7890.

Here we do see one drawback of the Bash associative array. Unlike an indexed array where the key list syntax will always output the valid keys in ascending numerical order, the associative array key order is essentially random. Even from noscript run to noscript run, the order can change, so if it matters, they should be sorted manually.

And it goes without saying that an associative array is ideal for storing a bunch of key-value
pairs as a mini-database. It is the equivalent to the hash table or dictionary data types of other languages.

\# EOF



https://redd.it/1kh6y9x
@r_bash
Just looking for general suggestions about my bootstrap noscript

Hi, I'm not looking for any advice in particular, just want to share my noscript and learn from people more experienced than me.

It's just a noscript I wrote some time ago to install some packages on my other Linux machines that evolved into a bootstrap for my system. Let me know what you think about it.

Here is the noscript

https://redd.it/1khfjq7
@r_bash
More Stupid Associative Array Tricks with Dynamic Array Names (Tiny Database)

Here's a somewhat contrived example of using named references and also using dynamically created variables - sort fo like an array of associative arrays. It also simulates daat entry from a terminal and will also run using terminal daat entered by hand, but it shows a good mix of named references and also dynamic variable definition, wihch i use a fair amout when getting variables set in side a configuration file such as:

options="-a -b -c"
directory="${HOME}/data"
file="some_data_file.data"

I can read the config file and set dynamic variables using the names. Reading and splitting them with a read and using IFS='=', rather than using an eval. I can also give them values by doing normal variable expansion using an echo:

declare ${config_var}=$( echo "${rvalue}" )

Anyway here's a fun little (well, kinda long with comments, maybe overengineered too) demo noscript I hacked together to show some os the dynamic naming and also using the `local -n` along with `${!variable}`.

#!/usr/bin/env bash
#------------------------------------------------------------------------------
# Bash Dynamic Array Names in Memory Database Example
#------------------------------------------------------------------------------
# This noscript demonstrates advanced Bash programming concepts by implementing
# a simple in-memory database using arrays. Key concepts demonstrated include:
#
# 1. Dynamic Variable Names
# - Uses bash's indirect reference capabilities
# - Shows how to create and manage variables dynamically
# - Demonstrates proper use of 'declare' for array creation
#
# 2. Associative Arrays
# - Each record is stored as an associative array (person_N)
# - Shows how to properly initialize and manage associative arrays
# - Demonstrates key-value pair storage and retrieval
#
# 3. Name References (nameref)
# - Uses 'declare -n' for creating references to arrays
# - Shows proper scoping and cleanup of namerefs
# - Demonstrates why namerefs need to be recreated in loops
#
# 4. Record Management
# - Implements basic CRUD operations (Create, Read, Update, Delete)
# - Uses a status array (person_index) to track record state
# - Shows soft-delete functionality (marking records as deleted)
#
# 5. Input Handling
# - Demonstrates file denoscriptor manipulation
# - Shows how to handle both interactive and automated input
# - Implements proper input validation
#
# Usage Examples:
# ./test -i # Interactive mode: Enter data manually
# ./test -t # Test mode: Uses predefined test data
#
# Database Structure:
# person_N - Associative array for each record (N = index)
# person_index - Tracks record status (E=exists, D=deleted)
# person_attributes - Defines the schema (field names)
# person_attr_display - Maps internal names to display names


# Will store state of each person record
# E = active employee, D = deleted employee
# Other flags could be added for indicating other states
declare -a person_index=()

# Define the attributes each person record will have
# This array defines the "schema" for our person records
# Simply add an attribute name to extend the table
declare -a person_attributes=(
"employee_id" # Unique identifier
"LastName" # Family name
"FirstName" # Given name
"email" # Contact email
)

# Display name mapping for prettier output
declare -A person_attr_display=(
[employee_id]="Employee ID"
[LastName]="Last Name"
[FirstName]="First Name"
[email]="Email"
)

# Test data for demonstration purposes and simulating user terminal input
TEST_DATA=$(cat << 'DATA'
Doe
John
john.doe@example.com
y
Smith
Jane
jane.smith@example.com
y