シェルスクリプト
https://betterdev.blog/minimal-safe-bash-script-template/
snippets
main
https://qiita.com/blackenedgold/items/c9e60e089974392878c8
print log
color
echo -e "$BIRed"$line"$Color_Off"
bash
括弧
[]と
[]はtestコマンドのalias
は強化版。以下のことができる。
・空白を含む文字列をクォートしなくてもOK(var="abc 123"のとき、 "$var"->$varでいい)
・正規表現が使える
・パターンマッチができる
・ANDやORに&&や||が使える
()と(())
():配列定義。var=(a b c)
(())は演算に使う。
{}と{{}}
{}
・変数展開(${var})
・パラメータ展開({a..c}等)に使う
・コマンドをまとめる
{{}}は使用することなさそう
$()と$(())
$()は``と同じでコマンド実行
$(())はインライン演算。(())と違ってインラインで使用できる
$系
docllar.sh abc 123と実行
dollar.sh
コマンドライン上で使える表現
!$:前回の引数を取得
service httpd restart
sudo !!
リダイレクト
標準エラー出力をリダイレクト
ls /home/bin 2> hoge.log
標準出力と標準エラー出力をリダイレクト
ls /home/bin &> hoge.log
ls /home/bin >& hoge.log
ls /home/bin > hoge.log 2>&1
teeで標準出力とファイルを両方に出力
ls /home/bin | tee hoge.log
exec
・出力をファイルに書く
exec &>file とすると以降のコマンド実行結果はすべてfileに書かれる
・任意のファイルディスクリプタを開く
exec 3> file
echo "hoge" >& 3
exec 3>&- # 閉じる
ヒアドキュメントでインデントしたい
<<-とする
ヒアストリングを使う
<<<
プロセス置換
プロセスの結果を一時ファイルのようにコマンドに渡すことができる機能
<()を使って一時ファイル不要diff
diff <(sort file1.txt | uniq) <(sort file2.txt | uniq)
EXITシグナルをフックする
エラーが起きた際に一時ファイルを消して終了したい場合等に使用する
trapコマンドを使う
trap 実行したいコマンド/関数 EXIT
bashパラメータ展開
シェルスクリプトを書く前に
シェルのオプションを設定する
http://itpro.nikkeibp.co.jp/article/COLUMN/20060227/230881/
set -ue
しておく
-u 未定義の変数を使った場合Stopする
-e エラーがあったらStopする
また、
#!/bin/sh -
とすると、
sh コマンドに、これ以上オプションが無いことを認識させます。
意図しないオプションをセットされることを防ぎます。
local変数を使うときは宣言したあとに使うこと。そうしないと関数の結果を代入したときにおかしくなる
使いやすいシェルスクリプト
http://deeeet.com/writing/2014/05/18/shell-template/
引数処理
https://translate.google.com/translate?hl=en&sl=ja&tl=en&u=http%3A%2F%2Fqiita.com%2Fb4b4r07%2Fitems%2Fdcd6be0bb9c9185475bb&anno=2&sandbox=1
getopt には重大な落とし穴があります。 それは、スペースや特殊文字が引数に含まれていた場合、正しく処理できないということです。 あるシェルスクリプトで getopt を使った場合、空白や特殊文字は絶対に使うな、という注意書きが必要になります。 これを何とかしのごうとするのは容易ではありません。
なので以下のようなものを自前で書く。しかし、-amのような使い方ができなくなる。特殊だが、2のような感じだとそれも解決できる。
1
2
シェルスクリプトでの実行確認
http://usaturn.net/memo/shell_tech_yesorno.html
よく使う構文
引数処理
いろいろな実行方法
sourceで実行
シェル変数の設定値は実行シェルには引き継がれない
.(ドットコマンド)で実行
sourceと同様
bash/shで実行
新しくシェルを起動して実行する。シェル変数の設定値は実行シェルには引き継がれる。
直接実行
シバンに記載されている別シェルで起動する。シェル変数の設定値は実行シェルには引き継がれる。
http://www.webzoit.net/hp/it/internet/homepage/env/cs/server/os/type/unix/linux/shell/kind/sh_bash/environment/
ファイル・ディレクトリ確認の演算子
演算子 | 説明 |
---|---|
-a ファイル | ファイルがあれば真 |
-b ファイル | ファイルがありブロックス特殊ファイルであれば真 |
-c ファイル | ファイルがありキャラクター特殊ファイルであれば真 |
-d ファイル | ファイルがありディレクトリであれば真 |
-e ファイル | ファイルがあれば真 |
-f ファイル | ファイルがあり通常のファイルであれば真 |
-g ファイル | ファイルがありSGID(特殊なアクセス権)であれば真 |
-G ファイル | ファイルがあり実行グループIDによる所有者であれば真 |
-h ファイル | ファイルがありシンボリックであれば真(-Lと同じ) |
-k ファイル | ファイルがありステッキービットが設定されていれば真 |
-L ファイル | ファイルがありシンボリックであれば真(-hと同じ) |
-O ファイル | ファイルがあり実行ユーザIDによる所有者であれば真 |
-p ファイル | ファイルがあり名前付きパイプ(named pipe)であれば真 |
-r ファイル | ファイルがあり読み取り可能であれば真 |
-s ファイル | ファイルがありサイズが0より大きければ真 |
-S ファイル | ファイルがありソケットであれば真 |
-t FD | FD(ファイルディスクリプタ)が端末でオープンされていれば真 |
-u ファイル | ファイルがありSUID(特殊なアクセス権)であれば真 |
-w ファイル | ファイルがあり書き込み可能であれば真 |
-x ファイル | ファイルがあり実行可能であれば真 |
https://www.server-memo.net/shellscript/file_check.html
デバッグ
プロンプト表示に行数、ファイル名を出すようにする
export PS4='+(${BASH_SOURCE}:${LINENO}): ${FUNCNAME:+$FUNCNAME(): }'
Trivia
linuxで、コマンドの引数に -(ハイフン)が指定できるのを見かけるけど、これ何?
答え
UNIXのシェルのコマンドラインでは、ハイフンひとつを標準入出力のことと読み替える習慣がある(絶対ではないが、そういう風にしている場合が多い)。
TroubleShooting
set -ue でexitするけど止まらない
exitを含む関数をlocal変数でうけているとだめらしい。localは戻り値が0になるらしい
local h h=$(hello)にすること
https://stackoverflow.com/questions/12840740/return-value-from-subshell-and-output-to-local-variables
Tips
ssh先で環境変数を設定するワンライナー
ssh -t xxx@yyy "bash -c 'export DISPLAY=192.168.1.100:0;bash'"
https://qiita.com/noexpect/items/e0e68610592874633653
同じカラムの最初の一致部分だけ簡単に抜き出す
awk '!colname[$1]++{print}'
sedで括弧内の文字列を抜き出す
rg "aaa\(" | sed "s/.*aaa(\(.*\)).*/\1/"
半角スペースがはいってるファイルから取り除く
find $1 -name "* *" -type f -print0 | while read -d $'\0' f; do mv -v "$f" "${f// /}"; done
太字(Bold)と斜体(Italic)をターミナルで表示する方法
まずフォントがBold対応、Italic対応しているか確認する。 fc-list
で使っているフォントにBold,Italicがあるか
あったら、ターミナルが対応しているか確認する
太字
echo -e '\033[1mBold\033[0m'
斜体echo -e "\e[3mItalic"
ProjectRoot(プロジェクトルート)を探す
basename $(git rev-parse --show-toplevel)
特定ディレクトリの下にある複数ファイルをglobで取得したい
find . -mindepth 2 -maxdepth 2 -type d -exec sh -c 'ls {}/AAA {}/BBBS' ; 2>/dev/null
sortコマンドの大文字小文字の順序を制御したい
https://superuser.com/a/178214
atqを実行時刻順でソートする
atq |sort -k 6n -k 3M -k 4n -k 5 -k 7 -k 1
シェルスクリプトの中からSQLを叩く
シングルクオートのエスケープができないためあとから置換する方法しかなさそう
atコマンド形式の時刻から普通の時刻に変換する
ヘッダーを含めずにsortする
https://stackoverflow.com/questions/14562423/is-there-a-way-to-ignore-header-lines-in-a-unix-sort/14562674
your_script | (sed -u 1q; sort)
これのsedの使い方がかっこいい。sed -u 1qで一行目だけ処理してあとをsortに回す
かっこいいカウントアップ
for ((i=0;; i++)); do printf '\r%s' $i; sleep .1; done
echoでの各ログレベルの色
INFO (Use default output color)
NOTICE 36 (Front color cyan)
WARNING 33 (Front color yellow)
ERROR 31 (Front color red)
https://github.com/rcmdnk/shell-logger
パイプで先頭のコマンドのプロセスIDを取得する
http://stackoverflow.com/questions/1652680/how-to-get-the-pid-of-a-process-that-is-piped-to-another-process-in-bash
これが一番よい気がする
配列を関数の引数にしたい
http://yomi322.hateblo.jp/entry/2012/07/15/122530
処理終了時にビープ音を鳴らしたい
echo ^G
tput bel
http://ja.stackoverflow.com/questions/230/%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89%E3%81%8C%E7%B5%82%E4%BA%86%E3%81%97%E3%81%9F%E3%82%89%E9%9F%B3%E3%82%92%E9%B3%B4%E3%82%89%E3%81%97%E3%81%9F%E3%81%84
ヘッダを除いてソートする
(head -n +1 sample.txt && tail -n +2 sample.txt | sort -k 2n,3n ) > sorted_sample.txt
対話的なコマンドを自動実行する
expect
evalで解決されないようにする
バックスラッシュでかわす
http://stackoverflow.com/questions/5253782/bash-problem-with-eval-variables-and-quotes
パイプでつながっているときの各戻り値を確認する
PIPESTATUS
http://kawa0810.hateblo.jp/entry/2015/01/12/213450
入力と同じファイルに出力する
echo "
uniq .bash_history" > .bash_history
{ rm .bash_history && uniq > .bash_history; } < .bash_history
uniq .bash_history | sponge .bash_history
install moreutils
http://serverfault.com/questions/135507/linux-how-to-use-a-file-as-input-and-output-at-the-same-time
ディストリビューションを判別する
1
OS=$(lsb_release -si)
ARCH=$(uname -m | sed 's/x86_//;s/i[3-6]86/32/')
VER=$(lsb_release -sr)
2
. /etc/lsb-release
OS=$DISTRIB_ID
ARCH=$(uname -m | sed 's/x86_//;s/i[3-6]86/32/')
VER=$DISTRIB_RELEASE
3
OS=$(uname -s)
ARCH=$(uname -m)
VER=$(uname -r)
4
5
which yum > /dev/null && { echo redhat; return; }
which zypper > /dev/null && { echo opensuse; return; }
which apt-get > /dev/null && { echo debian; return; }
例外処理を行う
0 or EXITは正常終了
ERRは0以外を指す
http://blog.suz-lab.com/2012/09/try-catch.html
今だけ必要なディレクトリ、ファイルを作る
mktempを使う
set -ueしているときに変数が定義されているかを判断する方法
デフォルト値を使う方法
http://masasuzu.hatenablog.jp/entry/2013/05/01/zsh_undefined_variable
-vを使う方法(bashのバージョンが4.2以上でなければならない)
set -ueしているときにコマンドの戻り値を評価する方法
http://sousaku-memo.net/php-system/1164
ふたつある
1つ目の方法set+e
最初に
set +e
目的のコマンド
set -e
をする方法
2つ目の方法if文[...]を使わない
[...] の代わりに直接コマンドを書くと戻り値を見てくれる模様
http://d.hatena.ne.jp/sasaplus1/20120621/1340207996
実行しているシェルスクリプトのパスを取得する
script_dir=$(cd $(dirname $0); pwd)
だとsourceした場合にうまく動かない
bashの場合は以下を使う
script_dir=$(cd $(dirname $BASH_SOURCE); pwd)
zshは以下
$0
ふたつとも使用出来る形式はこれ
script_dir=$(cd $(dirname ${BASH_SOURCE:-$0}); pwd)
set -x とコマンドを実行してしまった場合の解除方法
set +x
ファイルが存在していて開けるか確認
if test -r "$upFN" -a -f "$upFN";then
fi
スクリプトがあるディレクトリパスを取得
root_dir=(cd $(dirname $0); pwd)
予約済みexit code
Exit Code | 意味 | 例 | コメント |
---|---|---|---|
1 | 一般的なエラー全般 | $ let "var 1 = 1 / 0" | ゼロ除算などのコマンドを継続できない雑多なエラー |
2 | (Bash のドキュメントによると)シェルビルトインな機能の誤用 | $ empty_function(){} | キーワードのつけ忘れやコマンド,または権限周りの問題(あと, diffがバイナリファイルの比較に失敗した時 ) |
126 | 呼び出したコマンドが実行できなかった時 | $ /dev/null | パーミッションの問題かコマンドが executable でない時 |
127 | コマンドが見つからない時 | $ illegal_command | $PATHがおかしい時や typo した時などに起こる |
128 | exitコマンドに不正な引数を渡した時 | $ exit 3.14159 | exitコマンドは 0〜255 の整数だけを引数に取る |
128+n | シグナルnで致命的なエラー | $ kill -9 $PPID | 例では, $?は 137(128 + 9)を返す |
130 | スクリプトが Ctrl+C で終了 | Ctrl+C | Ctrl+C はシグナル2で終了する = 128 + 2 = 130(上記) |
255 | 範囲外の exit status | $ exit -1 | exitコマンドは 0〜255 の整数だけを引数に取る |
http://tldp.org/LDP/abs/html/exitcodes.html
Last updated