/Linuxコマンド

基本

シェルスクリプト

条件分岐・繰り返し・関数・引数・変数展開など、bash スクリプトを書くための組み込みコマンドと書き方。

スクリプトの先頭には、どのシェルで動かすかを書きます。

bash
#!/usr/bin/env bash
set -euo pipefail

chmod +x script.sh で実行権限を付け、./script.sh で実行します。

test / [ ] / [[ ]]条件を調べる

ファイルがあるか、文字列や数値が等しいかなどの条件を調べます。if と組み合わせて使います。

bash
if [ -f config.yml ]; then echo "ある"; fi
if [[ $name == lap* && -n $HOME ]]; then echo "一致"; fi   # [[ ]] は bash/zsh の拡張版
[ -d build ] || mkdir build
書き方意味
-e path / -f path / -d path存在する / ファイル / ディレクトリ
-r / -w / -x読める / 書ける / 実行できる
-s fileサイズが0より大きい
-L pathシンボリックリンク
f1 -nt f2f1 の方が新しい
-z "$s" / -n "$s"空 / 空でない
"$a" = "$b" / "$a" != "$b"文字列が等しい / 違う
$n -eq 1 / -ne / -lt / -le / -gt / -ge数値の比較
[[ $s =~ ^[0-9]+$ ]]正規表現に一致([[ ]] のみ)
[[ $s == *.txt ]]ワイルドカードに一致([[ ]] のみ)
! 条件 / && / ||否定 / かつ / または

if / case条件分岐

条件によって処理を分けます。

bash
if [ "$#" -eq 0 ]; then
echo "引数がありません" >&2
exit 1
elif [ "$1" = "-h" ]; then
usage
else
echo "引数: $1"
fi

case "$1" in
start|run)  echo "起動" ;;
stop)       echo "停止" ;;
*.txt)      echo "テキストファイル" ;;
*)          echo "不明: $1" ;;
esac

for / while / until繰り返し

同じ処理を繰り返します。ファイルを1つずつ処理したり、1行ずつ読んだりするのに使います。

bash
for f in *.jpg; do echo "$f"; done
for i in {1..5}; do echo "$i"; done
for ((i = 0; i < 3; i++)); do echo "$i"; done
for host in web1 web2 db1; do ssh "$host" uptime; done

while read -r line; do          # ファイルを1行ずつ読む
echo "行: $line"
done < list.txt

count=0
until [ $count -ge 3 ]; do count=$((count + 1)); done

while true; do date; sleep 5; done   # 無限ループ(Ctrl+C で止める)

break で抜け、continue で次の周回に進みます。

function / local / return関数を作る

よく使う処理に名前を付けてまとめます。

bash
greet() {
local name="${1:-world}"     # local で関数の中だけの変数にする
echo "hello, $name"
return 0                     # 終了コード(0〜255)。値を返すには echo を使う
}
greet alice
msg=$(greet)                   # 出力を受け取る

read入力を読む

キーボードからの入力や、ファイルの1行を変数に読み込みます。

bash
$ read -r -p "名前: " name
$ read -s -p "パスワード: " pw; echo    # 入力を表示しない
$ read -t 10 -p "10秒以内に: " ans       # タイムアウト
$ IFS=, read -r a b c <<< "1,2,3"       # 区切って変数に入れる
$ read -r -a arr <<< "x y z"             # 配列に入れる

shift / getopts引数を処理する

スクリプトに渡された引数やオプションを順に処理します。

bash
#!/usr/bin/env bash
verbose=0; out=out.txt
while getopts "vo:h" opt; do
case $opt in
v) verbose=1 ;;
o) out=$OPTARG ;;
h) echo "使い方: $0 [-v] [-o 出力] ファイル..."; exit 0 ;;
*) exit 1 ;;
esac
done
shift $((OPTIND - 1))          # 処理したオプションを取り除く
echo "残りの引数: $@"
変数意味
$0スクリプトの名前
$1 〜 $9、${10}位置引数
$#引数の数
"$@"すべての引数(1つずつクォートされる。基本はこちら)
"$*"すべての引数を1つの文字列に

set / shoptシェルの動きを変える

エラーで止める、実行するコマンドを表示するなど、シェルの動きを変えます。

書き方意味
set -eコマンドが失敗したら止まる
set -u未定義の変数を使ったらエラー
set -o pipefailパイプの途中の失敗も失敗とみなす
set -x実行するコマンドを表示する(デバッグ)
shopt -s globstar** でサブディレクトリまで一致させる
shopt -s nullglob一致するファイルがないとき、パターンを空にする
shopt -s dotglob* に隠しファイルも含める

trap終了時やシグナルで処理を走らせる

スクリプトが終わるときや中断されたときに、後片付けなどの処理を走らせます。

bash
tmp=$(mktemp -d)
trap 'rm -rf "$tmp"' EXIT          # 終わるとき(エラーでも)に片付ける
trap 'echo "中断しました"; exit 130' INT

declare配列・連想配列・型付きの変数

配列や連想配列などの変数を作ります。

bash
arr=(apple banana cherry)
echo "${arr[0]}"        # apple
echo "${arr[@]}"        # すべて
echo "${#arr[@]}"       # 要素の数
arr+=(date)             # 追加
for x in "${arr[@]}"; do echo "$x"; done

declare -A price        # 連想配列
price[apple]=100
price[banana]=80
for k in "${!price[@]}"; do echo "$k=${price[$k]}"; done

declare -i n=5          # 整数
declare -r PI=3.14      # 読み取り専用

mapfileファイルを配列に読み込む

ファイルの各行を配列に読み込みます。

bash
$ mapfile -t lines < list.txt
$ echo "${#lines[@]} 行"
$ mapfile -t files < <(find . -name '*.md')

変数の展開

書き方意味例(f=photo.tar.gz)
${var:-既定}空なら既定値を使う${NAME:-guest}
${var:=既定}空なら既定値を代入する
${var:?メッセージ}空ならエラーで止まる${1:?ファイルを指定}
${#var}文字数${#f} → 12
${var%.*}後ろから最短一致を削除photo.tar
${var%%.*}後ろから最長一致を削除photo
${var#*.}前から最短一致を削除tar.gz
${var##*.}前から最長一致を削除(拡張子)gz
${var/old/new}最初の一致を置換
${var//old/new}すべて置換${path// /_}
${var:0:5}部分文字列photo
${var^^} / ${var,,}大文字に / 小文字に

let / (( ))整数の計算

整数の計算をします。

bash
$ echo $((3 + 4 * 2))          # 11
$ n=5; ((n++)); echo $n         # 6
$ (( n > 3 )) && echo "大きい"
$ echo $((16#ff))               # 16進数 → 255
$ echo $((2 ** 10))             # べき乗

小数の計算は bc を使います。

exit / return終了コード

スクリプトや関数を終了し、成功・失敗を知らせます。

bash
exit 0          # 成功
exit 1          # 失敗(1〜255 のどれか)

直前のコマンドの終了コードは $? で分かります。cmd && echo 成功 || echo 失敗 のように使えます。

eval / execコマンドを組み立てて実行する

組み立てた文字列をコマンドとして実行したり、今のシェルを別のものに置き換えたりします。

bash
$ cmd="ls -l"; eval "$cmd"
$ exec > >(tee -a run.log) 2>&1     # 以降の出力をすべてログにも残す
$ exec zsh                           # 今のシェルを zsh に置き換える

waitバックグラウンドの処理を待つ

バックグラウンドで動かした処理が終わるのを待ちます。

bash
for h in web1 web2 web3; do
ssh "$h" 'apt update' &
done
wait            # すべて終わるまで待つ
echo "完了"

sleep待つ

指定した時間だけ待ちます。

bash
$ sleep 5        # 5秒
$ sleep 0.5      # 0.5秒
$ sleep 2m       # 2分(s・m・h・d)

true / false何もせず成功 / 失敗する

何もせず、成功または失敗を返します。

bash
while true; do ...; done
$ false || echo "失敗したので実行"

mktemp一時ファイルを安全に作る

一時ファイルや一時フォルダを、ほかと重ならない名前で安全に作ります。

bash
$ tmp=$(mktemp)              # /tmp/tmp.XXXXXXXX
$ dir=$(mktemp -d)           # 一時ディレクトリ
$ mktemp --suffix=.json

ヒアドキュメント・プロセス置換

bash
cat <<EOF            # 変数を展開する
こんにちは $USER
EOF

cat <<'EOF'          # 展開しない(そのまま)
$HOME はそのまま
EOF

cat <<-EOF           # 行頭のタブを取り除く
	インデントしても大丈夫
EOF

diff <(sort a.txt) <(sort b.txt)     # コマンドの出力をファイルのように渡す
grep foo <<< "$text"                 # 文字列を入力に渡す(ヒアストリング)

whiptail簡単なダイアログを出す

スクリプトから、端末上に選択肢や確認のダイアログを出せます。

bash
$ whiptail --yesno "続けますか?" 8 40 && echo "はい"
$ name=$(whiptail --inputbox "名前は?" 8 40 3>&1 1>&2 2>&3)
$ whiptail --menu "選んでください" 15 50 3 1 "起動" 2 "停止" 3 "状態" 3>&1 1>&2 2>&3