記事:
#!/bin/bash key=$1 array=( val1 val2 ) if printf '%s\n' "${array[@]}" | grep -qx "$key"; then echo "$key exists." else echo "$key does not exist." fi
echo -e "a.txt\nb.txt\n.dummy" > /tmp/ext.txt awk -F. '{print $NF}' /tmp/ext.txt | sort | uniq -c | sort -nr 2 txt 1 dummy
# シグナル一覧 trap -l # シグナルに設定されたtrapコマンドを表示 trap -p
trap " echo '`basename $0` end.' echo 'exit status: $?' " 0
trap sig_exit 0 sig_exit(){ echo "$(basename $0) end." echo "exit status: $?" }
echo 1.1 2.2 3.3 | awk '{printf "%s",$0}' 1.1 2.2 3.3 echo 1.1 2.2 3.3 | awk '{printf "%s",$1}' 1.1
echo 1.1 2.2 3.3 | awk '{printf "%d",$1}' 1
echo 1.101 2.2 3.3 | awk '{printf "%.2f",$1}' 1.10
echo 1.1 2.2 3.3 | awk '{printf "%4d",$1}' 1
echo 1.1 2.2 3.3 | awk '{printf "%04d",$1}' 0001
--ip-permissions "$(printf '[{"IpProtocol": "tcp", "FromPort": 24224, "ToPort": 24224, "IpRanges": [{"CidrIp": "%s", "Description": "%s"}]}]' "${AWS_EC2_SG_PUBLIC_CIDR}" "${AWS_EC2_SG_DESCRIPTION}")"
tsvで文字列を分割して取り出したいとき
echo -e "a\tb\t\t\te\t" > data.tsv
IFS= cat "data.tsv" | while read -r line || [ -n "${line}" ]; do echo "col[0]: $(cut -f1 <<<${line})" echo "col[1]: $(cut -f2 <<<${line})" echo "col[2]: $(cut -f3 <<<${line})" echo "col[3]: $(cut -f4 <<<${line})" echo "col[4]: $(cut -f5 <<<${line})" echo "col[5]: $(cut -f6 <<<${line})" done
bash tsv3.sh col[0]: a col[1]: b col[2]: col[3]: col[4]: e col[5]:
cat "data.tsv" | while IFS=$'\t' read -a cols || [ -n "${cols}" ]; do for ((i=0; i < ${#cols[@]}; i++)) { echo "col[$((i))]: ${cols[$i]}" } done
bash tsv.sh col[0]: a col[1]: b col[2]: e
-cat "data.tsv" | while IFS=$'\t' read -a cols || [ -n "${cols}" ]; do +cat "data.tsv" | tr "\t" "," | while IFS=$',' read -a cols; do
bash tsv2.sh col[0]: a col[1]: b col[2]: col[3]: col[4]: e
cat "data.tsv" | while IFS=$'\t' read a b c d e || [ -n "${a}" ]; do echo "a: ${a}, b: ${b}, c: ${c}, d: ${d}, e: ${e}" done
read -p "proceed ? (y/n)" answer;echo $answer proceed ? (y/n) y y
sudo yum install tmpwatch sudo cp my-tmpwatch /etc/cron.daily/ sudo chmod +x /etc/cron.daily/my-tmpwatch
type bash dummy;echo $? bash is /bin/bash -bash: type: dummy: not found 1
command -v bash dummy;echo $? /bin/bash 0
if ! $(type dig > /dev/null 2>&1); then echo -e "ERROR\tdig is not found." 1>&2 fi
if ! $(command -v $cmd > /dev/null); then echo -e "ERROR\t$cmd is not found." 1>&2 fi
for i in {1..10}; do name=$(printf file%02d.log $i); echo $name; done file01.log file02.log ... file10.log
bash -n example.sh
./parent.sh parent.sh::PID: 6307 run: 1, wait: 4, pid: 6310 run: 2, wait: 9, pid: 6311 run: 3, wait: 3, pid: 6312 wait child pid: 6310, exit: 4 wait child pid: 6311, exit: 9 wait child pid: 6312, exit: 3
tmp_path="/etc/httpd/conf/httpd.conf" tmp_file=${tmp_path##*/} # httpd.conf echo $tmp_file # httpd.conf echo ${tmp_file%.*} # httpd echo ${tmp_path%/*} # /etc/httpd/conf echo ${tmp_path##*.} # conf
選択式メニューを表示し、数字を入力するタイプ。
bash select-yes-no.sh 1) yes 2) no 3) all which ? > 1 1
#!/bin/bash get_nat_table_count(){ host=$1 password=$2 timeout=${3:-5} expect -c " set timeout $timeout spawn telnet $host expect \"Password:\" ; send \"$password\n\" expect \">\" ; send \"console character ascii\n\" expect \">\" ; send \"console lines infinity\n\" expect \">\" ; send \"show nat descriptor address\n\" expect \">\" ; send \"exit\n\" expect eof" | grep used | awk 'BEGIN {sum=0} {sum+=$6} END {print sum}' } HOST=192.168.1.1 PASSWORD=**** get_nat_table_count "$HOST" "$PASSWORD"
wait_connection() { local db_host=${1:-"127.0.0.1"} local db_user='root' local max_wait_sec=600 local wait_sec=10 local mysqladmin=/usr/bin/mysqladmin local start_sec=$SECONDS local end_sec=$SECONDS if [ -f "$mysqladmin" ]; then while [ $(( $end_sec - $start_sec )) -le $max_wait_sec ]; do $mysqladmin ping -u $db_user -h $db_host > /dev/null 2>&1 if [ $? == 0 ]; then break fi sleep $wait_sec end_sec=$SECONDS done else sleep $max_wait_sec fi return 0 }
echo $((1+2+3+4+5)) 15
echo "0.1*0.14*3" | bc .03 # 小数点3桁までをいれる echo "scale=3;0.1*0.14*3" | bc .042
# NG echo "scale=2; 199/10000*100" | bc 1.00 # OK echo "scale=2; 100*199/10000" | bc 1.99
echo "s(1)" | bc -l .84147098480789650665
true | false | (exit 3) | (exit 8) echo $? 8
true | false | (exit 3) | (exit 8) echo ${PIPESTATUS[@]} 0 1 3 8
crontab -e ---- * * * * * /usr/bin/flock -n /tmp/test.lock /tmp/test.sh $(date '+\%Y-\%m-\%d \%H:\%M:\%S') >> /tmp/test.log 2>&1 ----
#!/bin/bash export PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin readonly SCRIPT_NAME=$(basename $0) readonly LOCK_FILE=/tmp/${SCRIPT_NAME}.lock lock() { if [ -f $LOCK_FILE ]; then PID=$(cat $LOCK_FILE) if (ps -e | grep -P "^\s*$PID" >/dev/null); then echo $SCRIPT_NAME' is already running.' >&2 exit 1 fi fi echo $$ > $LOCK_FILE } unlock() { rm -f $LOCK_FILE } main() { lock for i in $(seq 1 7); do echo "PID=$$, seq:$i" sleep 10 done unlock } main
[ $$ != `pgrep -fo $0` ] && { echo 'Cannot run multiple instance.' >&2; exit 9; } # 実行結果 9188 /bin/sh -c /tmp/0.sh >> /tmp/0.log 2>&1 # cron で実行されたプロセス 9192 /bin/bash /tmp/0.sh # 子プロセス
#!/bin/bash callback() { local date=$1 echo $date } date_loop() { local callback=$1 local start=$2 local end=$3 while true; do eval "$callback $start" if [ "$start" == "$end" ]; then break; fi start=$(date "+%Y-%m-%d" -d "${start} 1 day") done } date_loop "callback" "2012-02-28" "2012-03-01"
2012-02-28 2012-02-29 2012-03-01
ls_result=$(ls) for temp in ${ls_result[@]};do echo ${temp} done
result=$(grep -l "hoge" $(ls *.sh))
# get_netstat_established_count # @param int port : tcp port # @return int count get_netstat_established_count() { local port=$1 local established_count=`netstat -nt | grep ":${port} " | grep "ESTABLISHED" | wc -l` echo $established_count }
command ... || { echo ... ; exit 1 ; }
mkdir tmp > /dev/null 2>&1 if [ $? -ne 0 ]; then echo "error" exit 1 fi
mkdir tmp > /dev/null 2>&1 || { echo "error" >&2; exit 1; }
bash --version | perl -ane 'if($.==1 && /version (\d+)\./){ print $1;}' # 3
var=`echo {0..10}` # 0 1 2 3 4 5 6 7 8 9 10 var=`echo {a..z}` # a b c d e f g h i j k l m n o p q r s t u v w x y z
if [ -z "$(ls -A ./dirname/)" ]; then echo "empty" else echo "not empty" fi
#/bin/bash # bash v4. "-A":連想配列を宣言 / "-a":数値配列 unset ary declare -A ary ary=( ["key1"]="value1" ["key2"]="value2" ["key3"]="value3" ) # 要素の追加 ary["key4"]="value4" ary+=( ["key5"]="value5" ) # 要素数 echo num: ${#ary[@]} # 5 # valueだけ欲しい for i in "${ary[@]}"; do echo $i done # key, valueも欲しい for i in "${!ary[@]}"; do echo $i, ${ary[$i]} done
まとめて標準入力、標準エラー、ファイル等に出せる
cat << EOS SHELL: $SHELL EOS
cat 1>&2 << EOS SHELL: $SHELL EOS
cat > file.tmp << 'EOS' hoge moke EOS
sudo tee file.tmp <<EOS >/dev/null hoge moke EOS
json=$(cat << EOD { "key1":"val1", "key2":"val2" } EOD ) echo $json | jq
mktemp /tmp/tmp.0FEIQ9u8mo mktemp /tmp/example.XXXXXX.tmp example.Os0Nne.tmp # ディレクトリ mktemp -d /tmp/example.XXXXXX.tmp
TMP_FILE=$$.tmp
#!/bin/bash loop(){ for i in {1..10}; do sleep 1 done } START_SEC=$SECONDS START_MSEC=`printf '%.3f' \`date '+%s.%N'\`` loop END_SEC=$SECONDS END_MSEC=`printf '%.3f' \`date '+%s.%N'\`` echo $(($END_SEC - $START_SEC))" s." echo `echo "scale=3;($END_MSEC - $START_MSEC)" | bc`" s."
bashで関数名だけ用意したい事があるが、空の関数は書くとエラーになる。
dummy(){ : } dummy
export TZ=JST-9 date '+%Y/%m/%d %H:%M:%S %Z'
#!/bin/bash str="" cat /etc/fstab | while read line; do str="$line"; break; # exit; done echo "str : $str"
#!/bin/bash str="" while read line; do str="$line";break; done < /etc/fstab echo "str : $str"
echo_success() echo_failure() echo_passed() echo_warning()
NIC0=`/sbin/ifconfig | grep eth0 | awk -- '(NR == 1){print $1}'`
/sbin/ifconfig eth0 | grep 'HWaddr' | awk -- '{print $5}'
/sbin/ifconfig eth0 | grep 'inet addr:' | awk -- '{print $2}' | awk -F':' -- '{print $2}'
cat >> example1.sh << 'EOS' func() { return 1 } # 呼び出し func EOS # 終了ステータス確認(1が返る) bash example1.sh echo $?
cat >> example2.sh << 'EOS' func() { echo "result-data" } result=`func` echo ${result} # result-data EOS
cat >> example3.sh << 'EOS' #!/bin/bash func() { echo "\$0=$0" # $0=example3.sh echo "\$#=$#" # $#=3 echo "\$@=$@" # $@=001 002 003 echo "\$*=$*" # $*=001 002 003 echo "\$1=$1" # $1=001 echo "\$2=$2" # $2=002 echo "\$3=$3" # $3=003 } func 001 002 003 EOS
cat >> example4.sh << 'EOS' #!/bin/bash GLOBAL=global func() { local GLOBAL=local echo $GLOBAL # local } func echo $GLOBAL # global EOS
HOME_USER=${SUDO_USER:-"$USER"} HOME_GROUP=`id $HOME_USER -g -n`
for F in *us.txt;do mv $F ${F/us./jp.};done
$min + $RANDOM % ( $max - $min )
expr 1 + $RANDOM % \( 10 - 1 \)
echo $(( 1 + $RANDOM % ( 10 - 1 ) ))
echo $(( 100/30 )) 3 echo $(( 100%30 )) 10
echo $(head -c 1k /dev/urandom | LANG=C tr -dc '[:alnum:]' | head -c 32) U2egJwX9m1WQyHMtaJpkrTuUdw2v71Bn
#/bin/bash # rand # @param int min : default 0 # @param int max : default 32767, max 32767 # @return int : rand() { local min=0 local max=32767 if [ $1 ]; then min=$1 fi if [ $2 ]; then max=$2 fi echo `echo $(( $min + $RANDOM % ( $max - $min ) ))` } # rand_str # @param int len : default 8 # @return int : rand_str() { local len=8 if [ $1 ]; then len=$1 fi echo `</dev/urandom tr -dc A-Za-z0-9 | head -c $len` } # rand_str_fast # @param int len : default 8, max 1000 # @return int : RANDSTRING=`</dev/urandom tr -dc A-Za-z0-9 | head -c 1000` # 1000文字まで作成しておく rand_str_fast() { local len=8 if [ $1 ]; then len=$1 fi local max=`echo $(( 1000 - $len ))` local start=`rand 1 $max` local end=`echo $(( $start + $len -1 ))` echo `echo -n "$RANDSTRING" | cut -c$start-$end` } for i in {1..10}; do echo `rand 1 10`,`rand_str_fast 8` done
2,8NOLYUIK 3,j7y74euW 3,5XG20fJ1 3,Cn5NGZwM 4,MKwbgRJO 7,BpeOCLZM 9,O9zbPunH 8,0j3cSLWd 6,yoExCkEX 8,OHEyoqeJ
for i in {1..10}; do echo $i done
LOOP=10 for i in `eval echo {1..$LOOP}`; do echo $i done
for i in $(seq -w 001 003); do echo $i done 001 002 003
for i in $(seq -w 001 003); do \ host=$(echo 'web$i' | perl -pe "s/\\$\i/$i/" ); \ echo $host; \ done web001 web002 web003
#!/bin/bash OS='' APACHE_USER='' get_os() { local os='' if [ -f /etc/debian_version ]; then os='debian' elif [ -f /etc/vine-release ]; then os='vine' elif [ -f /etc/turbolinux-release ]; then os='turbo' elif [ -f /etc/redhat-release ]; then local CHK=`egrep "CentOS .*release [5-6]|Red Hat Enterprise Linux .* [5-6]" /etc/redhat-release` if [ "$CHK" != '' ]; then os='rhel' fi else local os='' fi echo "$os" } get_apache_user() { local os=$1 local user='' if [ "$os" == "debian" ]; then user="www-data" elif [ "$os" == "rhel" ]; then user="apache" else user='' fi echo "$user" } OS=`get_os` APACHE_USER=`get_apache_user "$OS"` echo "OS: $OS" echo "APACHE_USER: $APACHE_USER"
#!/bin/bash :<<'#comment' echo hoge1 echo hoge2 #comment echo hoge3
hoge3
v=`httpd -v | perl -ane 'if( @F[2]=~/Apache\/(\d+\.\d+)/ ){ print $1; }'` r=`echo "$v >= 2.2" | bc` if [ $r -eq 1 ]; then echo "$v >= 2.2" else echo "$v < 2.2" fi
mysql_ver=$(mysql -V) # mysql Ver 14.14 Distrib 5.5.30, for Linux (x86_64) using readline 5.1 pattern='Distrib ([[:digit:]]\.[[:digit:]])' if [[ $mysql_ver =~ $pattern ]]; then echo ${BASH_REMATCH[0]} # Distrib 5.5 echo ${BASH_REMATCH[1]} # 5.5 fi
# -x:実行されたコマンドを表示する。変数も展開される。 bash -x test.sh # -v:実行されるコマンドを表示する。変数は展開されない。 bash -v test.sh
#!/bin/bash DEBUG=1 [ $DEBUG == 0 ] || { echo "debug";exit; }
set -e touch /tmp/foo/bar.txt # /tmp/foo ディレクトリが無い(exit status: 1)ので停止 echo success
set +e touch /tmp/foo/bar.txt exit_status=$? set -e echo $exit_status
set -eu echo $tmp_dir/bar.txt # $tmp_dir が未定義なため停止 echo success
set -eu # OK ARG1=${1:-} # NG: 「""」が変数に入ってしまう。 ARG1=${1:-""}
VAR1=2012-08-01 # 最後から最長一致 VAR2=${VAR1%%-*} # 2012 # 最後から最短一致 VAR2=${VAR1%-*} # 2012-08 # 最後の一文字を削除 VAR2=${VAR1/%?/} # 2012-08-0
VAR1=example.tar.gz # 左から最長一致 VAR2=${VAR1##*.} # gz # 左から最短一致 VAR2=${VAR1#*.} # tar.gz
test() { local var1; }
readonly VAR1=test1 VAR2=test2 VAR1=hoge1 # エラー VAR2=hoge2 # エラーにならない
{ echo "hoge" echo "fuga" echo "foo" echo "bar" } >>logfile.log # 最後を 1>&2 にすれば標準エラーにも吐ける
位置パラメータ $0 シェルスクリプト名を表示 $1〜$9 シェルスクリプトのオプションを表示(数値は位置を現す。10以降は${10}、${11}) 引数(オプション)関連 $# 引数の数を表示 $@ $0以外の全ての引数を表示("$@"にした場合は "$1" "$2" "…" のように展開) $* $0以外の全ての引数を表示("$*"にした場合は "$1 $2 ..." のように展開) $- シェルを起動する際に指定されていたオプションを表示 PID(プロセスID)関連 $? 直前のコマンドの終了ステータスを表示 0 : 正常 !0 : 失敗 2 : 誤った使用 126 : 実行できない 127 : 存在しないコマンドの実行 $$ 現在のシェルのプロセスIDを表示 $! 最期にバックグラウンドで実行されたコマンドのプロセスIDを表示 $- 現在のオプションフラグ その他、シェルスクリプトで使いそうなもの IFS フィールドの区切り文字 PWD カレントディレクトリを表示 PPID 親プロセスのプロセスIDを表示 HOME ホームディレクトリを表示 $SECONDS 秒 $RANDOM ランダム:0-32767 $LINENO 行番号 ${PIPESTATUS[@]} パイプで連結された各コマンドの終了ステータスの配列
IFS=$' \t\n'
IFS=$'\t'
#!/bin/bash IFS=',' read a b c d <<< 'a,b,,d' echo -e "a: $a\nb: $b\nc: $c\nd: $d"
NAME=$1 NAME2=${2:-"DEFAULT"} # NAMEが未定議 or nullの時、デフォルト値を指定。NAMEに代入されない。 echo ${NAME:-"DEFAULT"} echo "NAME:- $NAME" # NAMEが未定議 or nullの時、デフォルト値を指定。NAMEに代入される。 echo ${NAME:="DEFAULT"} echo "NAME:= $NAME" # NAMEが未定議 or nullの時、stderrに出力し、終了。 echo ${NAME:?"Error"} # NAMEが定義されている場合、変数に代入。空文字、未設定は空文字 echo ${NAME:+"word"} echo "NAME:+ $NAME"
#!/bin/bash # clear the screen tput clear # Move cursor to screen location X,Y (top left is 0,0) tput cup 3 15 # Set a foreground colour using ANSI escape tput setaf 3 echo "XYX Corp LTD." tput sgr0 tput cup 5 17 # Set reverse video mode tput rev echo "M A I N - M E N U" tput sgr0 tput cup 7 15 echo "1. User Management" tput cup 8 15 echo "2. Service Management" tput cup 9 15 echo "3. Process Management" tput cup 10 15 echo "4. Backup" # Set bold mode tput bold tput cup 12 15 read -p "Enter your choice [1-4] " choice tput clear tput sgr0 tput rc
# オプション部分を切り捨てる shift `expr $OPTIND - 1`
#!/bin/bash export LANG=C CMDNAME=`basename $0` usage_exit() { echo "Usage: $CMDNAME [-a] [-b VALUE] [-c VALUE]" 1>&2 exit 1 } echo "[DEBUG GLOBAL] \$# : $#" echo "[DEBUG GLOBAL] \$@ : $@" echo_debug() { echo "[DEBUG LOCAL] \$FLG_A : $FLG_A" echo "[DEBUG LOCAL] \$FLG_B : $FLG_B / $VALUE_B" echo "[DEBUG LOCAL] \$FLG_C : $FLG_C / $VALUE_C" } while getopts "a,b:,c:" OPT do case $OPT in "a" ) FLG_A="TRUE" ;; "b" ) FLG_B="TRUE" VALUE_B="$OPTARG" ;; "c" ) FLG_C="TRUE" VALUE_C="$OPTARG" ;; * ) usage_exit ;; esac done # オプション部分を切り捨てる shift `expr $OPTIND - 1` echo "[DEBUG GLOBAL] \$1 : $1" echo "[DEBUG GLOBAL] \$2 : $2" echo_debug
#!/bin/bash export LANG=C CMDNAME=`basename $0` usage_exit() { echo >&2 "Usage: $CMDNAME [-h|--hostname hostname] [-u|--hostuser username] [-s] [--longonly]" exit 1 } # check command args. if [ $# -lt 1 ]; then usage_exit fi echo "[DEBUG GLOBAL] \$# : $#" echo "[DEBUG GLOBAL] \$@ : $@" echo_debug() { echo "[DEBUG LOCAL] hostname : $hostname" echo "[DEBUG LOCAL] hostuser : $hostuser" echo "[DEBUG LOCAL] shortonly : $shortonly" echo "[DEBUG LOCAL] longonly : $longonly" } OPT=`getopt -q -o "h:,u:,s" -l "hostname:,hostuser:,longonly" -- "$@"` if [ $? != 0 ]; then usage_exit fi eval set -- "$OPT" while [ -n "$1" ]; do case $1 in -h|--hostname) hostname=$2; shift 2;; -u|--hostuser) hostuser=$2; shift 2;; -s) shortonly=1; shift 1;; --longonly) longonly=1; shift 1;; --) shift; break;; *) echo "Unknown option($1) used."; exit 1;; esac done echo "[DEBUG GLOBAL] \$1 : $1" echo "[DEBUG GLOBAL] \$2 : $2" echo_debug
if [ $EUID -eq 0 ]; then echo "root" fi
"$1 $2 ..."
"$1" "$2" ...
#/bin/bash hoge.php "$@"
#!/bin/bash a=( "aaa" "bbb" "c c c" ) #a[0]="aaa" #a[1]="bbb" #a[2]="c c c" for var in "${a[@]}"; do echo "${var}" done
aaa bbb c c c
main(){ for arg in "$@"; do echo $arg done } main "$@"
ARRAY=( "a" "b" "c" ) ARRAY2=${ARRAY[*]} echo ${ARRAY2[*]}
ARRAY1=() str1="a" str2="b" ARRAY1+=("$str1" "$str2")
${#ARRAY[*]}
CUR_DIR=$(cd $(dirname $0);pwd)
export PATH=$PATH:/usr/sbin:/sbin sh install.sh | tee install.log
MEM_TOTAL=`perl -e '$m=readpipe("free -m");$m=~/Mem:\s+(\d+)/i;print int($1)'` MEM_FREE=`perl -e '$m=readpipe("free -m");$m=~/cache:\s+(\d+)\s+(\d+)/i;print int($2)'`
echo "2012-01-01" | egrep '^[0-9]{4}\-[0-9]{2}\-[0-9]{2}$' > /dev/null || echo $?
match=`echo "$1" | egrep '^([0-9a-z\-]+)$' -` if [ $? != 0 ]; then echo "Error : Invalid character. allow [0-9, a-z, -]" exit fi