bashのsetコマンドで覚えておきたい使い方9個

シェルスクリプトを作る上で、以外と便利なのがsetコマンド。
オプションごとに関連性が薄いので覚えにくいのだが、使いこなせれば結構役に立つ事が多いコマンドだ。

今回は、そんなsetコマンドで覚えておきたい使い方についてを紹介する。

1.引数・オプションなしで実行(変数の一覧を表示する)

setコマンドは、引数無しで実行すると現在設定されている変数の一覧を表示させることが出来る。

set

[root@test-centos7 ~]# set
BASH=/bin/bash
BASHOPTS=checkwinsize:cmdhist:expand_aliases:extquote:force_fignore:histappend:hostcomplete:interactive_comments:login_shell:progcomp:promptvars:sourcepath
BASH_ALIASES=()
BASH_ARGC=()
BASH_ARGV=()
BASH_CMDS=()
BASH_LINENO=()
BASH_SOURCE=()
BASH_VERSINFO=([0]="4" [1]="2" [2]="45" [3]="1" [4]="release" [5]="x86_64-redhat-linux-gnu")
BASH_VERSION='4.2.45(1)-release'
COLUMNS=112
DIRSTACK=()
EUID=0
GROUPS=()
HISTCONTROL=ignoredups
HISTFILE=/root/.bash_history
HISTFILESIZE=1000
HISTSIZE=1000
HOME=/root
HOSTNAME=test-centos7
HOSTTYPE=x86_64
ID=0
IFS=$' \t\n'
LANG=ja_JP.UTF-8
LESSOPEN='||/usr/bin/lesspipe.sh %s'
LINES=36
LOGNAME=root
LS_COLORS='rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=01;05;37;41:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arc=01;31:*.arj=01;31:*.taz=01;31:*.lha=01;31:*.lz4=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.tzo=01;31:*.t7z=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.lrz=01;31:*.lz=01;31:*.lzo=01;31:*.xz=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.alz=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.cab=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.axv=01;35:*.anx=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=01;36:*.au=01;36:*.flac=01;36:*.mid=01;36:*.midi=01;36:*.mka=01;36:*.mp3=01;36:*.mpc=01;36:*.ogg=01;36:*.ra=01;36:*.wav=01;36:*.axa=01;36:*.oga=01;36:*.spx=01;36:*.xspf=01;36:'
MACHTYPE=x86_64-redhat-linux-gnu
MAIL=/var/spool/mail/root
MAILCHECK=60
OPTERR=1
OPTIND=1
OSTYPE=linux-gnu
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/bin:/root/bin
PIPESTATUS=([0]="0")
PPID=23637
PROMPT_COMMAND='printf "\033]0;%s@%s:%s\007" "${USER}" "${HOSTNAME%%.*}" "${PWD/#$HOME/~}"'
PS1='[\u@\h \W]\$ '
PS2='> '
PS4='+ '
PWD=/root
SELINUX_LEVEL_REQUESTED=
SELINUX_ROLE_REQUESTED=
SELINUX_USE_CURRENT_RANGE=
SHELL=/bin/bash
SHELLOPTS=braceexpand:emacs:hashall:histexpand:history:interactive-comments:monitor
SHLVL=1
SSH_CLIENT='XXX.XXX.XXX.XXX 52074 22'
SSH_CONNECTION='XXX.XXX.XXX.XXX 52074 YYY.YYY.YYY.YYY 22'
SSH_TTY=/dev/pts/0
TERM=xterm
UID=0
USER=root
XDG_RUNTIME_DIR=/run/user/0
XDG_SESSION_ID=8459
_=PATH
colors=/root/.dircolors
[root@test-centos7 ~]#
[root@test-centos7 ~]# set | grep TEST
[root@test-centos7 ~]# TEST=1234
[root@test-centos7 ~]# set | grep TEST
TEST=1234

2.実行するコマンドをコンソール上に出力する

「set -v」で実行するコマンドを、「set -x」でそのコマンドの変数等を展開した状態でコンソール上に表示させることが出来る。
(以下例の「printf ~」というのはPS1の表示を行っているもの)

[root@test-centos7 ~]# echo $HOME
/root
[root@test-centos7 ~]#
[root@test-centos7 ~]# set -v
printf "\033]0;%s@%s:%s\007" "${USER}" "${HOSTNAME%%.*}" "${PWD/#$HOME/~}"
[root@test-centos7 ~]# echo $HOME
echo $HOME
/root
printf "\033]0;%s@%s:%s\007" "${USER}" "${HOSTNAME%%.*}" "${PWD/#$HOME/~}"
[root@test-centos7 ~]# set +v
set +v
[root@test-centos7 ~]#
[root@test-centos7 ~]# set -x
++ printf '\033]0;%s@%s:%s\007' root test-centos7 '~'
[root@test-centos7 ~]# echo $HOME
+ echo /root
/root
++ printf '\033]0;%s@%s:%s\007' root test-centos7 '~'
[root@test-centos7 ~]# set +x
+ set +x

ちなみに、無効にする際はオプション値を「+」を使って記述してあげると良い。

3.シェルスクリプトの構文チェックだけを行わせる

シェルスクリプト内に「set -n」もしくは「set -o noexec」を記述することで、スクリプト実行時に構文チェックだけ行わせて、その中の処理を実行させないようにすることが出来る。
例えば、以下のように「set -n」を記述していないスクリプトを実行するとコマンドが実行されてしまうが、記述しているスクリプトだと構文チェックだけを行ってくれている。

[root@test-centos7 ~]# ls /tmp/test
[root@test-centos7 ~]# cat /work/test27.sh
#!/bin/bash
#set -n
mkdir "/tmp/test/test1234"
for fichier in `ls`
do
    if [[ -f "$fichier ]]; then
          echo "$fichier"
    fi
done
[root@test-centos7 ~]# cat /work/test28.sh
#!/bin/bash
set -n
mkdir "/tmp/test/test5678"
for fichier in `ls`
do
    if [[ -f "$fichier ]]; then
          echo "$fichier"
    fi
done
[root@test-centos7 ~]# bash /work/test27.sh
/work/test27.sh: 行 7: 一致する `"' を探索中に予期しないファイル終了 (EOF) です
/work/test27.sh: 行 10: 条件単項演算子に予期しない引数です
/work/test27.sh: 行 10: 構文エラー: 予期しないファイル終了 (EOF) です
[root@test-centos7 ~]# bash /work/test28.sh
/work/test28.sh: 行 7: 一致する `"' を探索中に予期しないファイル終了 (EOF) です
/work/test28.sh: 行 10: 条件単項演算子に予期しない引数です
/work/test28.sh: 行 10: 構文エラー: 予期しないファイル終了 (EOF) です
[root@test-centos7 ~]# ls /tmp/test
test1234

4.シェルスクリプト内で実行された処理が正常終了しない場合、処理を停止させる

シェルスクリプト内で「set -e」もしくは「set -o errexit」と記述することで、一部の処理を除いて、スクリプト内の実行コマンドが正常終了しなかった場合にスクリプトを即終了させる事が出来る。
例えば、以下の例の場合だと「set -e」が無いとエラーになった後の処理も実行されてしまうが、「set -e」が記述されていればそこで処理が止まっている。

[root@test-centos7 ~]# ls -la /tmp/TEST
ls: /tmp/TEST にアクセスできません: そのようなファイルやディレクトリはありません
[root@test-centos7 ~]# cat /work/test29.sh
#!/bin/bash
#set -e
mkdir /tmp/TEST1234/TEST
mkdir /tmp/TEST1234/TEST/1234
mkdir /tmp/TEST1234/TEST/5678
[root@test-centos7 ~]# cat /work/test30.sh
#!/bin/bash
set -e
mkdir /tmp/TEST1234/TEST
mkdir /tmp/TEST1234/TEST/1234
mkdir /tmp/TEST1234/TEST/5678
[root@test-centos7 ~]#
[root@test-centos7 ~]# bash /work/test29.sh
mkdir: ディレクトリ `/tmp/TEST1234/TEST' を作成できません: そのようなファイルやディレクトリはありません
mkdir: ディレクトリ `/tmp/TEST1234/TEST/1234' を作成できません: そのようなファイルやディレクトリはありません
mkdir: ディレクトリ `/tmp/TEST1234/TEST/5678' を作成できません: そのようなファイルやディレクトリはありません
[root@test-centos7 ~]# bash /work/test30.sh
mkdir: ディレクトリ `/tmp/TEST1234/TEST' を作成できません: そのようなファイルやディレクトリはありません

ただ、先ほども記述したように一部の処理(ループ内の処理だったり、三項演算子内だったりetc)については、正常終了でなくてもそのままスクリプトは実行されてしまうので注意が必要。

5.パス名の展開を無効にする

「set -f」もしくは「set -o noglob」を実行すると、シェルで「*(アスタリスク)」などでのワイルドカードでの展開を無効にする事ができる。

[root@test-centos7 ~]# ls /tmp/*
/tmp/*           /tmp/date_file   /tmp/tar_test.tar      /tmp/tar_test.tar.gz
/tmp/aaaaaa.log  /tmp/dddddd.log  /tmp/tar_test.tar.bz2  /tmp/test1

/tmp/test:
test1234

/tmp/test12345678:

/tmp/test2:
[root@test-centos7 ~]#
[root@test-centos7 ~]# set -f
[root@test-centos7 ~]# ls /tmp/*
/tmp/*
[root@test-centos7 ~]# set +f
[root@test-centos7 ~]# ls /tmp/*
/tmp/*           /tmp/date_file   /tmp/tar_test.tar      /tmp/tar_test.tar.gz
/tmp/aaaaaa.log  /tmp/dddddd.log  /tmp/tar_test.tar.bz2  /tmp/test1

/tmp/test:
test1234

/tmp/test12345678:

/tmp/test2:

6.ブレース展開を無効にする

「set +B」もしくは「set +o braceexpand」で、シェルのブレース展開を無効にする事ができる。

[root@test-centos7 ~]# echo abc{123,456,789}def
abc123def abc456def abc789def
[root@test-centos7 ~]#
[root@test-centos7 ~]# set +B
[root@test-centos7 ~]# echo abc{123,456,789}def
abc{123,456,789}def

7.リダイレクト時の上書きを無効にする

「set -C」および「set -o noclobber」を実行すると、リダイレクト時のファイルへの上書き(追記はできる)を無効にすることが出来る。
(ただし、「>|」を用いると上書き可能になっている)

[root@test-centos7 ~]# echo 0 > /tmp/aaaaa
[root@test-centos7 ~]# cat /tmp/aaaaa
0
[root@test-centos7 ~]#
[root@test-centos7 ~]# echo 01 > /tmp/aaaaa
[root@test-centos7 ~]# cat /tmp/aaaaa
01
[root@test-centos7 ~]#
[root@test-centos7 ~]# set -C
[root@test-centos7 ~]#
[root@test-centos7 ~]# echo 0123 > /tmp/aaaaa
-bash: /tmp/aaaaa: 存在するファイルを上書きできません
[root@test-centos7 ~]# echo 0123 >> /tmp/aaaaa
[root@test-centos7 ~]# cat /tmp/aaaaa
01
0123
[root@test-centos7 ~]#
[root@test-centos7 ~]# echo 0123 >| /tmp/aaaaa
[root@test-centos7 ~]# cat /tmp/aaaaa
0123

8.引数を指定し直す

setコマンドにオプション無しで引数を渡すと、スクリプトの引数を設定し直す事が出来る。

[root@test-centos7 ~]# set 1234 5678
[root@test-centos7 ~]# echo $2
5678
[root@test-centos7 ~]# echo $1
1234
[root@test-centos7 ~]#
[root@test-centos7 ~]# cat /work/test31.sh
#!/bin/bash
set abcdef ghijk 12345
echo $1
echo $3
echo $2
[root@test-centos7 ~]#
[root@test-centos7 ~]# bash /work/test31.sh
abcdef
12345
ghijk
[root@test-centos7 ~]# bash -x /work/test31.sh
+ set abcdef ghijk 12345
+ echo abcdef
abcdef
+ echo 12345
12345
+ echo ghijk
ghijk

9.現在のオプション状態を確認する

setコマンドで設定したオプション値を確認する場合、ただ「set -o」と実行することでその一覧を確認出来る。

[root@test-centos7 ~]# set -o
allexport       off
braceexpand     on
emacs           on
errexit         off
errtrace        off
functrace       off
hashall         on
histexpand      on
history         on
ignoreeof       off
interactive-comments    on
keyword         off
monitor         on
noclobber       on
noexec          off
noglob          off
nolog           off
notify          off
nounset         off
onecmd          off
physical        off
pipefail        off
posix           off
privileged      off
verbose         off
vi              off
xtrace          off