Preface
The $ character is used for parameter expansion, and command substitution. You can use it for manipulating and/or expanding variables on demands without using external commands such as sed or awk.
#1: Getting Up Default Shell Variables Value
The syntax is as follows:
- ${parameter:-defaultValue}
- var=${parameter:-defaultValue}
- u=${1:-root}
- t1.sh
- #!/bin/bash
- _jail_dir="${1:-/home/phpcgi}"
- echo "Setting php-cgi at ${_jail_dir}..."
- # rest of the script ...
Here is another handy example:
- _mkdir(){
- local d="$1" # get dir name
- local p=${2:-0755} # get permission, set default to 0755
- [ $# -eq 0 ] && { echo "$0: dirname"; return; }
- [ ! -d "$d" ] && mkdir -m $p -p "$d"
- }
#1.1: Setting Default Values
The syntax is as follows:
- ${var:=value}
- var=${USER:=value}
Tip: ${var:-defaultValue} vs ${var:=defaultValue}
Please note that it will not work with positional parameter arguments:
- var=${1:=defaultValue} ### FAIL with an error cannot assign in this way
- var=${1:-defaultValue} ### Perfect
If the variable is not defined or not passed, you can stop executing the Bash script with the following syntax:
- ${varName?Error varName is not defined}
- ${varName:?Error varName is not defined or is empty}
- ${1:?"mkjail: Missing operand"}
- MESSAGE="Usage: mkjail.sh domainname IPv4" ### define error message
- _domain=${2?"Error: ${MESSAGE}"} ### you can use $MESSAGE too
- _domain="${1:?Usage: mknginxconf domainName}"
- #!/bin/bash
- # Purpose: Wrapper script to setup Nginx Load Balancer
- # Author: Vivek Gite
- _root="/nas.pro/prod/scripts/perl/nginx"
- _setup="${_root}/createnginxconf.pl"
- _db="${_root}/database/text/vips.db"
- _domain="${1:?Usage: mknginxconf domainName}" ### die if domainName is not passed ####
- [ ! -f $_db ] && { echo "$0: Error $_db file not found."; exit 1; }
- line=$(grep "^${_domain}" $_db) || { echo "$0: Error $_domain not found in $_db."; exit 2; }
- # Get domain config info into 4 fields:
- # f1 - Domain Name|
- # f2 - IPv4Vip:httpPort:HttpsPort, IPv6Vip:httpPort:HttpsPort|
- # f3 - PrivateIP1:port1,PrivateIP2,port2,...PrivateIPN,portN|
- # f4 - LB Type (true [round robin] OR false [session])
- # -------------------------------------------------------------------------------
- IFS='|'
- read -r f1 f2 f3 f4 <<<"$line"
- # Do we want ssl host config too?
- IFS=':'
- set -- $f2
- ssl="false"
- [ "$3" == "443" ] && ssl="true"
- # Build query
- d="$f1:$ssl:$f4"
- IFS=','
- ips=$f3
- # Call our master script to setup nginx reverse proxy / load balancer (LB) for given domain name
- $_setup "$d" $ips
If $2 is not set display an error message for $2 parameter and run cp command on fly as follows:
- #!/bin/bash
- _file="$HOME/.input"
- _message="Usage: chkfile commandname"
- # Run another command (compact format)
- _cmd="${2:? $_message $(cp $_file $HOME/.output)}"
- $_cmd "$_file"
You can easily find string length using the following syntax:
- ${#variableName}
- echo ${#variableName}
- len=${#var}
- #!/bin/bash
- # Usage : Add a ftp user
- _fuser="$1"
- _fpass="$2"
- # die if username/password not provided
- [ $# -ne 2 ] && { echo "Usage: addftpuser username password"; exit 1;}
- # Get username length and make sure it always <= 8
- [[ ${#_fuser} -ge 9 ]] && { echo "Error: Username should be maximum 8 characters in length. "; exit 2;}
- # Check for existing user in /etc/passwd
- /usr/bin/getent passwd "${_fuser}" &>/dev/null
- # Check exit status
- [ $? -eq 0 ] && { echo "Error: FTP username \"${_fuser}\" exists."; exit 3; }
- # Add user
- /sbin/useradd -s /sbin/nologin -m "${_fuser}"
- echo "${_fpass}" | /usr/bin/passwd "${_fuser}" --stdin
#4: Remove Pattern (Front of $VAR)
The syntax is as follows:
- ${var#Pattern}
- ${var##Pattern}
- f="/etc/resolv.conf"
- echo ${f#/etc/}
- _version="20090128"
- _url="http://dns.measurement-factory.com/tools/dnstop/src/dnstop-${_version}.tar.gz"
Now try using the longest part of the pattern syntax:
This is also useful to get a script name without using /bin/basename:
- #!/bin/bash
- _self="${0##*/}"
- echo "$_self is called"
- #!/bin/bash
- # Purpose: Display jail info as per softlink
- # Author: Vivek Gite
- _j="$@"
- # find out script name
- _self="${0##*/}"
- [ "$VERBOSE" == "1" ] && echo "Called as $_self for \"$_j\" domain(s)"
- for j in $_j
- do
- export _DOMAIN_NAME=$j
- source functions.sh
- init_jail
- # call appropriate functions as per script-name / softlink
- case $_self in
- uploaddir.info) echo "Upload dir for $j: $(get_domain_upload_dir)" ;;
- tmpdir.info) echo "/tmp dir for $j: $(get_domain_tmp_dir)" ;;
- mem.info) echo "$j domain mem usage (php+lighttpd): $(get_domain_mem_info)" ;;
- cpu.info) echo "$j domain cpu usage (php+lighttpd): $(get_domain_cpu_info)" ;;
- user.info) echo "$j domain user and group info: $(get_domain_users_info)" ;;
- diskquota.info) echo "$j domain disk quota info (mysql+disk): $(get_domain_diskquota_info)" ;;
- *) warn "Usage: $_self"
- esac
- done
You can now call script as follows:
#4.1: Remove Pattern (Back of $VAR)
The syntax is as follows:
- ${var%pattern}
- ${var%%pattern}
Rename all *.perl files to *.pl using bash for loop as Apache web server is configured to only use .pl file and not .perl file names:
- for p in /scripts/projects/.devl/perl/*.perl
- do
- mv "$p" "${p%.perl}.pl"
- done
- #!/bin/bash
- # Usage: Build suhosin module for RHEL based servers
- # Author: Vivek Gite
- # ----
- # Set default value for $2
- VERSION="-${2:-0.9.31}"
- URL="http://download.suhosin.org/suhosin${VERSION}.tgz"
- vURL="http://download.suhosin.org/suhosin${VERSION}.tgz.sig"
- # Get tar ball names
- FILE="${URL##*/}"
- vFILE="${vURL##*/}"
- DLHOME="/opt"
- SOFTWARE="suhosin"
- # Remove .tgz and get dir name
- DEST="${FILE%.tgz}"
- # Download software
- wget $URL -O "${DLHOME}/$FILE"
- wget $vURL -O "${DLHOME}/$vFILE"
- # Extract it
- tar -zxvf $FILE
- cd "$DEST"
- # Build it and install it
- phpize --clean && phpize && ./configure && make && read -p "Update/Install $SOFTWARE [Y/n] ? " answer
- shopt -s nocasematch
- [[ $answer =~ y|es ]] && make install
- shopt -u nocasematch
#5: Find And Replace
The syntax is as follows:
- ${varName/Pattern/Replacement}
- ${varName/word1/word2}
- ${os/Unix/Linux}
You can avoid using sed as follows:
To replace all matches of pattern, enter :
- out="${x//unix/linux}"
- y=/etc/resolv.conf
- cp "${y}" "${y/.conf/.conf.bak}"
- # RHEL php modules path
- _php_modules="/usr/lib64/php/modules"
- for i in $_php_modules/*
- do
- p="${i##*/}" ## Get module name
- ini="/etc/php.d/${p/so/ini}" ## Get ini file by replacing .so with .ini extension
- # make sure file exists
- [ ! -f "$ini" ] && echo "$i php module exists but $ini file not found."
- done
- install_php_modules(){
- # get jail name
- local n="${_chrootbase}/${d##/}"
- local p=""
- local ini=""
- # enable only ${_php_modules_enabled} php modules and delete other .ini files if exists in jail
- for i in $_php_modules/*
- do
- p="${i##*/}"
- ini="$n/etc/php.d/${p/so/ini}"
- # find out if module is enabled or not
- if [[ ${_php_modules_enabled} = *${p}* ]]
- then
- [ "$VERBOSE" == "1" ] && echo " [+] Enabling php module $p"
- $_cp -f "$i" "$n/${_php_modules##/}" ## install it
- copy_shared_libs "$i" ## get shared libs in jail too
- else
- [ -f "${ini}" ] && $_rm -f "${ini}" ## if old .ini exists in jail, just delete it
- fi
- done
- }
The syntax is as follows:
- ${parameter:offset}
- ${parameter:offset:length}
- ${variable:position}
- var=${string:position}
Below will extract word 'craft' only:
- x="nixcraft.com"
- echo ${x:3:5}"
For your ready references here are all your handy bash parameter substitution operators. Try them all; enhance your scripting skills like a pro:
沒有留言:
張貼留言