Bash¶
#!/bin/bash
set -e
set -o pipefail
# https://stackoverflow.com/a/246128/1061279
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
SCRIPT_NAME=$(basename "${0}")
ROOT_DIR="$(git rev-parse --show-toplevel)"
readonly DIR
readonly SCRIPT_NAME
readonly ROOT_DIR
Generate Password¶
sudo apt install apache2-utils
echo $(htpasswd -nB user) | sed -e s/\\$/\\$\\$/g
# user:passwordhash
Files¶
Delete all files matching a pattern in sub folders
find . -name "*.lock" -type f -delete
Clear an already existing file
>|file.txt
Search root for the name
sudo find / -name file.txt
Create a new blank file
touch file.txt
Get file size in bytes
wc -c file.txt
Get the size in bytes of a compressed file
gzip -c file.txt | wc -c
bzip2 -c file.txt | wc -c
tar -cf - file.txt | wc -c
Validate JSON¶
cat foo.json | jq empty
parse error: Expected separator between values at line 154, column 30
Remove File Extension¶
name=$(echo "$filename" | cut -f 1 -d '.')
# or
echo "${filename%%.*}"
Extract filename and extension in Bash¶
~% FILE="example.tar.gz"
~% echo "${FILE%%.*}"
example
~% echo "${FILE%.*}"
example.tar
~% echo "${FILE#*.}"
tar.gz
~% echo "${FILE##*.}"
gz
Full File Path¶
readlink -f file.txt
Checks¶
# Check if chart dir exists
if [ -d "${CHART_PATH}" ]; then
echo "Chart path already exists, ${CHART_PATH}"
exit 1
fi
# Check if i2c-tools is installed
if ! command -v git &> /dev/null; then
echo "git is not installed"
exit 1
fi
Check if substring is in string
string='My long string'
if [[ $string == *"My long"* ]]; then
echo "It's there!"
fi
Check empty variable
if [ -z "${REPOSITORY}" ]; then
echo "Could not get the repository"
exit 1
fi
Single line checks
# Check is variable is null
function is_null {
[ -z "$1" ]
}
# Check if directory exists
function dir_exists(){
[ -d "${1}" ]
}
# Check if command exists
function command_exists(){
command -v "${1}" &> /dev/null
}
is_null "$left" && echo "is null"
String manipulation¶
VAR=$(basename "/tmp/file.txt")
VAR="${VAR: -1}"
VAR="${VAR::-1}"
Get domain without the .com
http://user:[email protected]:80/some/path/url?data&and#hash
-> example
# https://unix.stackexchange.com/a/428990/93726
echo "http://user:[email protected]:80/some/path/url?data&and#hash" | sed -e "s/[^/]*\/\/\([^@]*@\)\?\([^:/]*\).*/\2/" | sed "s/^www\.//" | cut -f 1 -d '.'
s=${var%% *}
s="${var// /-}"
s="${var,,}"
s="${var#*.}"
s="${var##*.}"
s="${var%%.*}"
s="${var%.*}"
Checksums¶
Get checksum of remote file
wget -qO- https://github.com/nicholaswilde/helm-template/archive/main.zip | sha256sum
echo "62df608caba8f2591755f99efac0097c3d7acf313e237e328aa2c046d500efd1 main.zip" | sha256sum -c
Scripts¶
Get single options, -v, -h, etc.
# https://www.jamescoyle.net/how-to/1774-bash-getops-example
# https://opensource.com/article/19/12/help-bash-program
# Get the options
while getopts ":hv" o; do
case "${o}" in
h) # display Help
help
exit 0;;
v)
printf "${SCRIPT_NAME} version ${APP_VERSION}\n"
exit 0;;
\?) # incorrect option
usageerror;;
esac
done
# https://unix.stackexchange.com/a/214151/93726
shift "$((OPTIND-1))"
Miscellaneous¶
printf
printf "%s is the value" "${var}"
# Expand the tab, \t or new line \n
var="value\t"
printf "%b is the value" "${var}"
Insert first line of file
sed -i '1i text' filename
Delete a tmp dir on exit
# https://stackoverflow.com/a/687052/1061279
trap 'rm -rf -- "$TMP_DIR"' EXIT
Download and extract file in one line. Works with tar & zip files.
wget -qO- https://github.com/nicholaswilde/helm-template/archive/main.zip | bsdtar -xvf-
Make variable global from inside function
eval VAR="value"
Compare semver
# https://stackoverflow.com/a/4025065/1061279
function vercomp () {
if [[ $1 == $2 ]]; then
return 0
fi
local IFS=.
local i ver1=($1) ver2=($2)
# fill empty fields in ver1 with zeros
for ((i=${#ver1[@]}; i<${#ver2[@]}; i++)); do
ver1[i]=0
done
for ((i=0; i<${#ver1[@]}; i++)); do
if [[ -z ${ver2[i]} ]]; then
# fill empty fields in ver2 with zeros
ver2[i]=0
fi
if ((10#${ver1[i]} > 10#${ver2[i]})); then
return 1
fi
if ((10#${ver1[i]} < 10#${ver2[i]})); then
return 2
fi
done
return 0
}
function testvercomp () {
vercomp $1 $2
case $? in
0) op='=';;
1) op='>';;
2) op='<';;
esac
if [[ $op != $3 ]]; then
echo "The minimum required version of git is $2"
exit 1
fi
}
testvercomp ${GIT_VER} ${MIN_VER} '>'
Generate Random String¶
cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 64 | head -n 1
Function Library¶
#!/bin/bash
# Load the myfunctions.sh
# My local path is /home/vivek/lsst2/myfunctions.sh
. /home/vivek/lsst2/myfunctions.sh
# Define local variables
# var1 is not visitable or used by myfunctions.sh
var1="The Mahabharata is the longest and, arguably, one of the greatest epic poems in any language."
# Invoke the is_root()
is_root && echo "You are logged in as root." || echo "You are not logged in as root."
# Find out if user account vivek exits or not
is_user_exits "vivek" && echo "Account found." || echo "Account not found."
# Display $var1
echo -e "*** Orignal quote: \n${var1}"
# Invoke the to_lower()
# Pass $var1 as arg to to_lower()
# Use command substitution inside echo
echo -e "*** Lowercase version: \n$(to_lower ${var1})"
Run As Different User¶
sudo -u "${TARGET_USER}" bash <<"EOF9"
command
EOF9
Return Value from Function¶
function myfunc(){
local myresult='some value'
echo "$myresult"
}
result=$(myfunc) # or result=`myfunc`
echo $result
Sort Semver Using Sort¶
printf "1.0\n2.0\n2.12\n2.10\n1.2\n1.10" | sort -t "." -k1,1n -k2,2n -k3,3n
1.0
1.2
1.10
2.0
2.10
2.12
ID (Debian, Ubuntu)¶
echo $(. /etc/os-release && echo $ID)
Arch¶
Subs aarch64
with arm64
, x86_64
with amd64
, and armv7l
and armv6l
with arm
ARCH=$(uname -m | sed -e 's/x86_64/amd64/' -e 's/\(arm\)\(64\)\?.*/\1\2/' -e 's/aarch64$/arm64/')
echo $ARCH
Subs aarch64
with arm64
, x86_64
with amd64
, and armv7l
and armv6l
with armhf
ARCH=$(uname -m | sed -e 's/x86_64/amd64/' -e 's/\(arm\)\(64\)\?.*/\1\2hf/' -e 's/aarch64$/arm64/')
echo $ARCH
Check if system needs to be restarted¶
sudo needrestart
We use the systemctl command as follows to restart services one-by-one:
sudo systemctl restart nginx
sudo systemctl restart firewalld
We can use bash for loop as follows:
for s in systemd-udevd firewalld polkit sshd nginx; do
sudo systemctl restart "$s"
done
How to restart systemd with PID # 1 without rebooting Linux box
sudo systemctl daemon-reexec
And verify it again:
sudo lsof | grep 'DEL.*lib' | cut -f 1 -d ' ' | sort -u
Check Array for Value¶
if [[ " ${array[*]} " =~ " ${value} " ]]; then
# whatever you want to do when array contains value
fi
if [[ ! " ${array[*]} " =~ " ${value} " ]]; then
# whatever you want to do when array doesn't contain value
fi
Search for string in files¶
grep -R <stringToSearch> <dirName>
If you want to get number of occurrences use wc -l as pipe
grep -R "text" . | wc -l
Print Colors & Bold¶
bold=$(tput bold)
normal=$(tput sgr0)
blue=$(tput setaf 4)
echo "this is ${bold}bold${normal} but this isn't"
for c in {0..255}; do tput setaf $c; tput setaf $c | \cat -v; echo =$c; done | column
See here for colors.
Bypass Alias¶
A simple directive which disables all aliases and functions for the command immediately following it. Shortcut for the bash built-in 'command' - "command linefoo".
\foo
Push your present working directory to a stack that you can pop later¶
pushd /tmp
```shell titl="Remove directory from stack" popd
## Run script in subshell
```shell
sudo -u "${TARGET_USER}" bash <<"EOF"
cd "$HOME"
mkdir -p "${HOME}/git/nicholaswilde/"
git clone https://github.com/nicholaswilde/dotfiles.git "${HOME}/git/nicholaswilde/dotfiles"
cd "${HOME}/git/nicholaswilde/dotfiles"
# set the correct origin
git remote set-url origin [email protected]:nicholaswilde/dotfiles.git
# installs all the things
make
EOF
Get IPv4¶
grep -o '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}'
Show Environmental Variables¶
printenv
printenv | less
printenv | more
Show Shell Functions¶
declare -F | awk '{print $3}' | grep -v '^_'
Show Shell Aliases¶
alias
Replace Tabs with Spaces¶
sed -i 's/\t/ /g' tab-file.txt
Git Status¶
git diff --quiet; nochanges=$?
if [ $nochanges -eq 0 ]; then
# there are no changes
else
# there are changes
fi
Alternatively, if you don't need to store the exit status in a variable, you can do:
if git diff --quiet; then
# there are no changes
else
# there are changes
fi
Since git diff is a porcelain Git command and you want to do things programmatically, you should probably use the plumbing Git command called git diff-index instead (which also has a --quiet flag, but which must be supplied a tree-ish argument):
if git diff-index --quiet HEAD; then
# there are no changes
else
# there are changes
fi
As pointed out in a comment below, the approach outlined above does not cover untracked files. To cover them as well, you can use the following instead:
if [ -z "$(git status --porcelain)" ]; then
# there are no changes
else
# there are changes
fi
Relative Path¶
Using realpath from GNU coreutils 8.23 is the simplest, I think:
realpath --relative-to="$file1" "$file2"
For example:
realpath --relative-to=/usr/bin/nmap /tmp/testing
../../../tmp/testing
Get Between Patterns¶
aaa
bbb
pattern1
aaa pattern2
bbb
ccc
pattern2
ddd
eee
pattern1
fff
ggg
sed -n '/^pattern1/,/^pattern2/{p;/^pattern2/q}'
sed -n '/^pattern1/,${p;/^pattern2/q}'
Test if option is set¶
If you do set -f
, or otherwise disable globbing:, $-
will contain f
:
$ echo $-
himBHs
$ set -f
$ echo $-
fhimBHs
$ bash -fc 'echo $-'
fhBc
So:
[[ $- = *f* ]]
Or:
case $- in
*f*) ... ;;
esac