Skip to content

Instantly share code, notes, and snippets.

@shebin512
Last active November 7, 2020 19:06
Show Gist options
  • Save shebin512/648f7ac12f0e4b1f45c5f4c6a17da8d6 to your computer and use it in GitHub Desktop.
Save shebin512/648f7ac12f0e4b1f45c5f4c6a17da8d6 to your computer and use it in GitHub Desktop.
Bash script tips and tricks
#!/bin/sh -x
# Backup and delete files in list file
[ $# -lt 1 ] && { echo "INPUT FILE NAME MISSING!"; exit 1; }
INPUT_FILE=$1
[ -f $INPUT_FILE ] || { echo "INPUT FILE NOT EXIST"; exit 1; }
#Commands
mkdir -pv ~/bakup_`date +%F`
## Back up and remove the in list
for file in $(cat $INPUT_FILE)
do
if [ -f $file ]
then
echo $i;
/bin/cp -vR $file ~/backup_`date +%F`/ --parents;
/bin/rm -i $file;
fi
done
#!/usr/bin/env bash
# https://opensource.com/article/18/5/bash-tricks
# History related
ctrl + r (reverse search)
!! (rerun last command)
!* (reuse arguments from previous command)
!$ (use last argument of last command)
shopt -s histappend (allow multiple terminals to write to the history file)
history | awk 'BEGIN {FS="[ \t]+|\\|"} {print $3}' | sort | uniq -c | sort -nr | head (list the most used history commands)
# File and navigation
cp /home/foo/realllylongname.cpp{,-old}
cd -
rename 's/text_to_find/been_renamed/' *.txt
export CDPATH='/var/log:~' (variable is used with the cd built-in.)
# Colourize bash
# enable colors
eval "`dircolors -b`"
# force ls to always use color and type indicators
alias ls='ls -hF --color=auto'
# make the dir command work kinda like in windows (long format)
alias dir='ls --color=auto --format=long'
# make grep highlight results using color
export GREP_OPTIONS='--color=auto'
export LESS_TERMCAP_mb=$'\E[01;31m'
export LESS_TERMCAP_md=$'\E[01;33m'
export LESS_TERMCAP_me=$'\E[0m'
export LESS_TERMCAP_se=$'\E[0m' # end the info box
export LESS_TERMCAP_so=$'\E[01;42;30m' # begin the info box
export LESS_TERMCAP_ue=$'\E[0m'
export LESS_TERMCAP_us=$'\E[01;36m'
# Bash shortcuts
shopt -s cdspell (corrects typoos)
ctrl + _ (undo)
ctrl + arrow (move forward a word)
ctrl + a (move cursor to start)
ctrl + e (move cursor to end)
ctrl + k (cuts everything after the cursor)
ctrl + l (clears screen)
ctrl + q (resume command that is in the foreground)
ctrl + s (pause a long running command in the foreground)
ctrl + t (swap two characters)
ctrl + u (cuts everything before the cursor)
ctrl + x + ctrl + e (opens the command string in an editor so that you can edit it before it runs)
ctrl + x + * (expand glob/star)
ctrl + xx (move to the opposite end of the line)
ctrl + y (pastes from the buffer)
ctrl + shift + c/v (copy/paste into terminal)
# Running commands in sequence
&& (run second command if the first is successful)
; (run second command regardless of success of first one)
# Redirecting I/O
2>&1 (redirect stdout and stderr to a file)
# check for open ports
echo > /dev/tcp/<server ip>/<port>
`` (use back ticks to shell out)
# Examine executable
which <command>
file <path/to/file>
command -V <some command binary> (tells you whether <some binary> is a built-in, binary or alias)
#!/bin/bash
CURRENT_PHP_VERSION=$(php -r "echo phpversion();"|cut -c1-3)
NEW_PHP_VERSION=$1
a2dismod php$CURRENT_PHP_VERSION
a2enmod php$NEW_PHP_VERSION
service apache2 restart
update-alternatives --set php /usr/bin/php$NEW_PHP_VERSION
#update-alternatives --set php-fpm /usr/bin/php$NEW_PHP_VERSION-fpm
#update-alternatives --set phar /usr/bin/phar$NEW_PHP_VERSION
#update-alternatives --set phar.phar /usr/bin/phar.phar$NEW_PHP_VERSION
#update-alternatives --set phpize /usr/bin/phpize$NEW_PHP_VERSION
#update-alternatives --set php-config /usr/bin/php-config$NEW_PHP_VERSION
#!/usr/bin/env bash
#
# Simple rsync profiler
#
# Author: petrberanek.mail@gmail.com (Petr Beranek)
#
# For usage details type `rpf --help'
#
# https://opensource.com/article/20/1/create-save-run-rsync-configurations
set -o errexit
set -o nounset
__name=$(basename "${0}")
__version="0.1"
config_dir="${HOME}/.rpf"
profiles_dir="${config_dir}/profiles"
shared_dir="${config_dir}/shared"
help="\
Usage: ${__name} [OPTION...] PROFILE_NAME
${__name} is simple rsync profiler that stores your different rsync
configurations in named profiles.
Options:
-c, --create-profile PROFILE_NAME create new profile (profile data
are stored in ${config_dir}/PROFILE_NAME).
Profile name can contain alphanumeric
characters only.
-s, --show-profile-config PROFILE_NAME show content of profile
configuration file (stored in
${config_dir}/PROFILE_NAME)
-l, --list-profiles list all available profiles
-h, --help show this help
Example:
Create new profile by typing
${__name} -c PROFILE_NAME
edit its config files stored by default in
${profiles_dir}/PROFILE_NAME
and then run it by typing
${__name} PROFILE_NAME
That's it.
${__name} comes with ABSOLUTELY NO WARRANTY. This is free software,
and you are welcome to redistribute it under certain conditions. See
the GNU General Public Licence for details.
Email bug reports or enhancement requests to petrberanek.mail@gmail.com.
"
create_profile() {
# Create dir with given profile name and with default content.
#
# Arguments: $1 -- profile name
#
# Creates files: conf, exclude
#
# If dir with the same name already exists, exits with error.
#
local profile_name="${1}"
local profile_dir="${profiles_dir}/${profile_name}"
# create default rpf dirs if missing
if [[ ! -d "${profiles_dir}" ]]; then
echo "Creating ${profiles_dir}"
mkdir --parents "${profiles_dir}"
fi
if [[ ! -d "${shared_dir}" ]]; then
echo "Creating ${shared_dir}"
mkdir --parents "${shared_dir}"
fi
# don't overwrite existing profile
if [[ -d "${profile_dir}" ]]; then
echo "${__name}: error: profile already exists."
exit 1
fi
echo "Creating ${profile_dir}"
mkdir "${profile_dir}"
# create `conf' template
local conf="${profile_dir}/conf"
echo "Creating ${conf}"
cat << EOF > "${conf}"
# rsync config template
#
# Write each rsync option on separate line. For details see man rsync.
# Empty lines and lines starting with # are ignored. Dynamic references
# (e.g. using command substitution) are not supported.
#
# Config files shared between different profiles should be saved in
# ${shared_dir}
#
# Example configuration:
#
--verbose
--archive
--human-readable
# file with patterns of files and directories in source excluded
# from transfer
--exclude-from="${profiles_dir}/${profile_name}/exclude"
--relative
# perform trial run, make no changes
--dry-run
# source, e.g.
${HOME}
# destination, e.g.
/mnt/usb_drive/my_backup
EOF
# create `exclude' template
local exclude="${profile_dir}/exclude"
echo "Creating ${exclude}"
cat << EOF > "${exclude}"
# \`exclude' template
#
# Lines starting with # or ; are ignored. For details see man rsync,
# section FILTER RULES.
#
EOF
# all done
echo "OK"
echo "Edit profile config files in ${profile_dir} to fit your needs."
}
list_profiles() {
# Show all available rpf profiles.
#
# Assumes that all dirs in $profiles_dir are profiles.
#
for item in "${profiles_dir}"/*; do
if [[ -d "${item}" ]]; then
basename "${item}"
fi
done
}
show_help() { echo "${help}"; }
show_profile_config() {
# Show configuration file for given profile.
#
# Arguments: $1 -- profile name
#
local profile_name="${1}"
less "${profiles_dir}/${profile_name}/conf"
}
check_profile_name() {
# Check that name is not empty and contains alphanumeric chars only.
#
# Arguments: $1 -- profile name
#
# If test fails, exits with error.
#
if [[ -z "${1}" ]]; then
echo "${__name}: error: empty profile name."
exit 1
elif [[ "${1}" =~ [^a-zA-Z0-9] ]]; then
echo "${__name}: error: non-alphanumeric characters in profile name."
exit 1
fi
}
check_profile_exists() {
# Check that $profile_name exists and is a directory.
#
# Arguments: $1 -- profile name
#
# If test fails, exits with error.
#
local profile_name="${1}"
if [[ ! -d "${profiles_dir}/${profile_name}" ]]; then
echo "${__name}: error: profile ${profile_name} does not exist."
exit 1
fi
}
check_num_args() {
# Check that value of $1 = number of arguments (excluding $1)
#
# Arguments: $1 -- limit (positive int)
#
# If test fails, exits with error.
#
local num_args=$(( ${#} - 1 )) # do not count $1 in total num of args
if [[ "${1}" -ne "${num_args}" ]]; then
echo "${__name}: error: expected num args: ${1}, received: $num_args"
exit 1
fi
}
run_rsync() {
# Run rsync with configuration coresponding to given profile name.
#
# Arguments: $1 -- profile name
#
local profile_name="${1}"
local visual_div="=============================="
local parsed_args
parsed_args=$(grep --invert-match '^#' "${profiles_dir}/${profile_name}/conf" \
| tr '\n' ' ')
# Print debug info
echo "${visual_div}"
echo "${__name} version: ${__version}"
echo "args: ${parsed_args}"
echo "${visual_div}"
# Expand $parsed_args - each item from conf file becomes rsync argument
# shellcheck disable=SC2086
rsync ${parsed_args}
}
if [[ "${#}" == 0 ]]; then
show_help
exit 1
fi
while [[ "${#}" -gt 0 ]]; do
case "${1}" in
-c | --create-profile)
check_num_args 2 "${@}"
shift
check_profile_name "${1:-}" # If $1 is not declared, set it empty.
create_profile "${1}"
exit 0;;
-s | --show-profile-config)
check_num_args 2 "${@}"
shift
check_profile_name "${1:-}"
check_profile_exists "${1}"
show_profile_config "${1}"
exit 0;;
-l | --list-profiles)
check_num_args 1 "${@}"
list_profiles
exit 0;;
-h | --help)
check_num_args 1 "${@}"
show_help
exit 0;;
-*)
echo "${__name}: error: unknown option \`${1}'"
exit 1;;
*)
check_num_args 1 "${@}"
check_profile_name "${1:-}"
check_profile_exists "${1}"
run_rsync "${1}"
exit 0;;
esac
shift
done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment