POSIX シェルの小ネタ集。随時更新。
POSIX の範囲外の機能に依存するところには 【non-POSIX】 と書いておいた。
ファイル操作
空のファイルを作る
touch
でもいいがリダイレクトした方が速い。
>> filename # 既存ファイルは上書きしない (ファイルの更新日時も変へない)
>| filename # 既存ファイルは空にする
> filename # -C が有効なら既存ファイルがあるとエラーになる
フィルタ
ソートして重複行を消す
sort | uniq
でもいいが sort -u
だと一コマンドで済む。
ソートせずに重複行を消す
awk '!x[$0]++'
1
行番号を付加する
awk '{print ++i,$0}'
【non-POSIX】 cat -n
一行目だけを消す
tail -n +2
sed 1d
最後の行だけを消す
head -n -1
sed \$d
n 行目だけを出す
sed -n 5p
(5 行目だけを出す)
sed -n 4,6p
(4 行目から 6 行目だけを出す)
行の順序を逆にする
sed -n '1h;1!{x;H;};${g;p;}'
2
awk '{line[NR]=$0} END {for (i=NR; i>=1; i--) print line[i]}'
2
【non-POSIX】 tac
一行づつ読み込んで、それぞれを引数として特定のコマンドを実行する
空白でも区切られるとか "
や \
がエスケープになるとかを気にしないのであれば
xargs -n 1 [command]
厳密に各行をそのまま読み取ってコマンドに渡したいときは
while IFS= read -r line; do
[command] "$line"
done
文字列操作
不特定の文字列を出力する
echo
を使ふと実装によっては先頭のハイフンがオプションと見做されたりバックスラッシュがエスケープと見做されたりして思ひ通りに出力されないことがある。printf
を使った方が良い。
printf '%s\n' "${any_char}"
文字列が glob パターンに一致するか調べる
case
を使ったマッチングはあまり見慣れないかもしれないがどんなシェルでも使へる。
case abc in (a*c)
echo matched!
esac
【non-POSIX】[[ ... ]]
文は一部のシェルでしか使へない。[[ ... ]]
の代はりに [ ... ]
を使ってはいけない。
if [[ abc = a*c ]]; then
echo matched!
fi
文字列が正規表現に一致するか調べる
grep
の終了ステータスで一致したかどうかがわかる。
if echo abc | grep -q 'a.*c'; then
echo matched!
fi
【non-POSIX】[[ ... ]]
文は一部のシェルでしか使へない。[[ ... ]]
の代はりに [ ... ]
を使ってはいけない。
if [[ abc =~ a.*c ]]; then
echo matched!
fi
パス操作
不特定のパスに相対パスを連結する
"${base%/}/${rel}"
詳細は別記事を見よ。
相対パスを絶対パスにする
【non-POSIX】でも良ければ readlink
といふコマンドが使へる。
POSIX 範囲内で頑張るには、cd
で対象のディレクトリーに移動した後 pwd
で絶対パスを出力する。パスがディレクトリーでない場合はその前に dirname
と basename
でパスを分割しておく。
abs_dir=$(cd "./$rel_dir" && pwd -P)
シェル実行環境操作
一時的に別のディレクトリーで作業する
cd -
で一つ前のディレクトリーに戻れる。ただしスタックを pop するかの様に複数回戻ることはできない。
cd foo
# foo ディレクトリーで作業...
cd -
# 元のディレクトリーで作業...
サブシェルなら入れ子にできる。ただしサブシェル内で代入した変数などを外側で使ふことはできない。
(
cd foo
# foo ディレクトリーで作業...
(
cd bar
# foo/bar ディレクトリーで作業...
)
# foo ディレクトリーで作業...
)
# 最初のディレクトリーで作業...