Bash (Bourne again Shell) is a shell for running commands on a Unix or Linux system.
Repeating Historical commands
$ !! # last command again
$ !find # last command starting with 'find' again
$ file `!!` # show the file type for the file found in the previous command
$ ^file^cat # redo previous command but replace 'file' with 'cat'
Get part of a variable (substring)
Pull out parts of a substring:
str="2023-10-12"
echo "${str:5:2}" # 10
echo "${str::4}" # 2023
echo "2022-${str:5}" # 2022-10-12
Can even get substrings from right side using a negative index:
str="backup.sql"
echo "original${str:(-4)}" # original.sql
String replacement
str="obin-linux_x64_bin"
echo "${str/x64/armhf}" # obin-linux_armhf_bin
echo "${str/bin/dist}" # odist-linux_x64_bin
echo "${str//bin/dist}" # odist-linux_x64_dist
Can also do it to file names and paths:
str="db_config_backup.zip"
echo "${str/%.zip/.conf}" # db_config_backup.conf
echo "${str/#db/settings}" # settings_config_backup.zip
Can also match with a wildcard:
str="db_config_backup.zip"
echo "${str/%.*/.bak}" # db_config_backup.conf
echo "${str/#*_/new}" # newbackup.zip
String regex
You can use grep and sed but faster is the inbuilt if match with =~ that is a bash built-in:
str="db_backup_2003.zip"
if [[ $str =~ 200[0-5]+ ]]; then
echo "regex_matched"
fi
Once bash does a regex match, it typically stores all matches in the BASHREMATCH shell variable. This variable is a read-only array, and it stores the entire matched data in the first index. If you use sub-patterns, Bash incrementally keeps those matches in other indexes:
str="db_backup_2003.zip"
if [[ $str =~ (200[0-5])(.*)$ ]]; then
echo "${BASH_REMATCH[0]}" # 2003.zip
echo "${BASH_REMATCH[1]}" # 2003
echo "${BASH_REMATCH[2]}" # .zip
fi
Similarly, can use a regex to do find and replace:
str="db_backup_2003.zip"
re="200[0-3].zip"
echo "${str/$re/new}.bak" # db_backup_new.bak