とあるエンジニアの備忘log
ラベル
shell
の投稿を表示しています。
すべての投稿を表示
ラベル
shell
の投稿を表示しています。
すべての投稿を表示
2012年12月15日土曜日
標準エラー出力をファイルに落としたい (teeの標準エラー出力版)
`tee` というコマンドがあります。 「標準入力から読んだ内容を標準出力とファイルに書きだす」というものです。 例えば、 $ foo | tee logfile とすると、 `foo` コマンドの標準出力は、 `logfile` に書き出されます。 なおかつ、標準出力は標準出力として、標準エラー出力は標準エラー出力として出力されます。 ログを記録するときには便利なコマンドですね。 そこで思ったのは、 `tee` コマンドの標準エラー版に相当するものを実現できないかと思いました。 コンパイルのときの warning とかは通常、標準エラー出力へ出てきます。 標準エラー出力をファイルに記録しておいて、 warning を潰していくのに使いたいのです。 で、考えたシェルスクリプトが以下です。 #!/bin/sh exec 3>&1 foo 2>&1 >&3 3>&- | tee logfile >&2 `foo` コマンドの標準エラー出力を `logfile` に書き出します。 なおかつ、標準出力は標準出力として、標準エラー出力は標準エラー出力として出力されます。 `m>&n` は 「`n` 番の出力先と同じものを `m` 番へコピーする (`dup2` する)」という意味です。 `m>&-` は 「`m` 番を閉じる」という意味です。 また、 `exec` は引数にコマンドが与えられていない場合、リダイレクト処理はカレントシェルで効果を表します。 つまり、上記のスクリプトは、 `foo` コマンドの標準出力と標準エラー出力を入れ替えて、 パイプに流し、さらに `tee` コマンドの標準出力(= `foo` コマンドの標準エラー出力) を標準エラー出力に戻す、ということをしています。 (後日、bash なら `foo |& tee logfile >&2` のように簡単に書けることを知った。。) さらに、 `foo` が異常終了した場合に、即座にシェルスクリプトを止めたいときは、以下のようにします。 パイプに渡してしまうと、そのままでは終了ステータスを取れませんので、ちょっと複雑になっております。。 #!/bin/sh exec 3>&1 status=$({ { foo 2>&1 >&3 3>&- 4>&-; echo $? 1>&4 3>&- 4>&-;} | tee log >&2 3>&- 4>&- ;} 4>&1) if [ "$status" != "0" ]; then set -e /bin/false fi bash の `$PIPESTATUS` の実現方法は[こちらのページ](http://x68000.q-e-d.net/~68user/unix/pickup?%A5%EA%A5%C0%A5%A4%A5%EC%A5%AF%A5%C8)で勉強させていただきました。
2012年12月4日火曜日
シェルで四則演算
### 方法1 ### 16進数は使えません。 $ expr 1 + 1 2 $ expr 0x10 + 0x0F expr: 整数でない引数 ### 方法2 ### 16進数も使える。 $ echo $(( 1 + 1 )) 2 $ echo $(( 0x10 + 0x0F )) 31 ### 方法3 ### bashの場合は以下も可。 $ echo $[ 1 + 1 ] 2 $ echo $[ 0x10 + 0x0F ] 31 ### 方法4 ### bash の場合、以下のようなこともできるらしい。 $ i=0 $ echo $i 0 $ ((i++)) $ echo $i 1
2012年6月19日火曜日
シェル制御文まとめ
### if 文 ### if command-list then command-list [elif command-list then command-list ] [else command-list ] fi ### for 文 ### for variable [ in word-list ] do command-list done ### while 文 ### while command-list do command-list done ### case 文 ### case string in [ pattern [ | pattern ] ... ) command-list;; ] [ pattern [ | pattern ] ... ) command-list;; ] ...... esac 上記の `command-list` の部分は、改行もしくは `;` で区切れば複数のコマンドを書くことができます。 `[ ... ]` はあってもなくてもいい部分です。 一行で書く時は以下の通り。 ブラウザで見たときに折り返ってるかもしれませんが、一行と思ってください。 ### if 文 ### if command-list; then command-list; [elif command-list; then command-list;] [else command-list; ] fi ### for 文 ### for variable [ in word-list; ] do command-list; done ### while 文 ### while command-list; do command-list; done ### case 文 ### case string in [ pattern [ | pattern ] ... ) command-list;; ] [ pattern [ | pattern ] ... ) command-list;; ] ...... esac シェルスクリプトを書くときに一行で書く人はいないでしょうが、 makefile など一行で書かないといけないときがあるので、理解しておく必要があります。 どこに `;` を入れるかは、覚えておかなくても理屈で考えればわかります。 if test -r foo; then みたいなのは、 `;`がなかったら `then` までが `test` の引数だと解釈されてしまいます。 なので、基本的に `command-list` の後には `;`がいります。 逆に `then` とか `else` とか `do` みたいに、制御用の予約語の後は、 `;` がなくても構文解釈できますので、不要なわけです。 ### Here Documents ### command <
シェル変数まとめ その2
- `$?` 直前に実行したコマンドの終了ステータス - `$$` 現在動作しているコマンドのプロセスID - `$!` 直前のバックグラウンドジョブのプロセスID 例) $ emacs & [1] 2814 $ emacs & [2] 2816 $ echo $! 2816 - `$-` カレントシェルで設定されているフラグ 例) $ echo $- himBH $ bash -r $ echo $- himrBH - `$#` 位置パラメーターの数 - `$*` 位置パラメータの全部 - `$@` `$*` と同じだが、 `"$@"` のようにクォーティングすると、各位置パラメータも個別にクォーティングされる - `$0` - `$9` 各位置パラメータ。 $0 はコマンド名称を表す 位置パラメータ関係は、シェルスクリプトの引数処理でよく使いますね。 以下の例では対話的にやってますが。 set で位置パラーメータを設定できます。 例) $ set a b c d $ echo $0 bash $ echo $1 a $ echo $2 b $ echo $# 4 $ echo $* a b c d $ echo $@ a b c d $ set "a b" c d $ echo $1 a b $ echo $# 3 $ echo $* a b c d $ echo $@ a b c d $ echo "$*" a b c d $ echo "$@" a b c d $ ls "$*" ls: a b c d にアクセスできません: そのようなファイルやディレクトリはありません $ ls "$@" ls: a b にアクセスできません: そのようなファイルやディレクトリはありません ls: c にアクセスできません: そのようなファイルやディレクトリはありません ls: d にアクセスできません: そのようなファイルやディレクトリはありません 例題中の `"$*"` は `"a b c d"` に `"$@"` は `"a b" "c" "d"` に展開されています。 `echo "$*"` と `echo "$@"`は同じ結果が表示されていますが、 `ls "$*"` と `ls "$@"` は解釈のされ方が違いますね。 以下は bash でのみ使える機能だが、 - `$_` 直前のコマンドの第1引数を返す。 `mkdir -p path/to/new/dir; cd $_` のように使う。
2012年6月14日木曜日
シェル変数まとめ その1
- `${variable:=value}` 変数 `variable` が空でなければ、 `variable` の値を返す。 空なら、 `variable` に `value` を代入し、`value` を返す。 - `${variable=value}` 変数 `variable` が定義済みなら、 `variable` の値を返す。 未定義なら、 `variable` に `value` を代入し、`value` を返す。 - `${variable:-value}` 変数 `variable` が空でなければ、 `variable` の値を返す。 空なら、 `value` を返す。代入処理は行わない。 - `${variable-value}` 変数 `variable` が定義済みなら、 `variable` の値を返す。 未定義なら、 `value` を返す。代入処理は行わない。 - `${variable:?message}` 変数 `variable` が空でなければ、 `variable` の値を返す。 空なら、 `message` を表示し、シェルスクリプト中ならその場で終了する。 - `${variable?value}` 変数 `variable` が空でなければ、 `variable` の値を返す。 空なら、 `message` を表示し、シェルスクリプト中ならその場で終了する。 - `${variable:+value}` 変数 `variable` が空でなければ、 `value` を返す。 空なら、空文字列を返す。 - `${variable+value}` 変数 `variable` が定義済みなら、 `value` を返す。 未定義なら、空文字列を返す。 `:` (コロン)ありの場合は変数が空でないかどうかで判定するのに対し、`:` (コロン)なしの場合は定義済かどうかで判定します。 例 $ FOO= # 空にする $ echo ${FOO:=123} # 空なので 123 # 123 を返す $ echo $FOO 123 # 代入もされてる $ echo ${FOO:=456} # 今度は空ではないので 123 # FOOの値 (123)を返す $ FOO= # 空にする $ echo ${FOO=456} # 空ですが、定義はされてるので # FOO の値 (NULL) を返す $ echo $FOO # 代入もされていない $ unset FOO # 未定義に戻すには unset します $ echo ${FOO=456} # 未定義なので 456 # 456 を返す $ `=` と `-` の違いは、 `-` は代入まではしないことです。 $ FOO= # 空にする $ echo ${FOO:-123} # 空なので 123 # 123 を返す $ echo $FOO # ただし代入はされてない $ `+` は `-` とは反対のような機能ですね。 $ FOO= # 空にする $ echo ${FOO:+123} # 空なので # 空を返す $ FOO=456 # 何か値を入れる $ echo ${FOO:+123} # 空ではないので 123 # 123 を返す $ echo $FOO 456 # 代入はされません あと、こんなんもあります。 - `${variable#value}` `variable` の値の前から `value` を削ったものを返す。最短のマッチ。 - `${variable##value}` `variable` の値の前から `value` を削ったものを返す。最長のマッチ。 - `${variable%value}` `variable` の値の後ろから `value` を削ったものを返す。最短のマッチ。 - `${variable%%value}` `variable` の値の後ろから `value` を削ったものを返す。最長のマッチ。 例) $ FOO=foo/bar/baz $ echo ${FOO#foo/} # 前方の foo/ を削ります。 bar/baz $ echo ${FOO#*/} # ワイルドカードも使えます。前方の */ を削ります。(最短のマッチ) bar/baz $ echo ${FOO##*/} # 前方の */ を削ります。(最長のマッチ) baz $ echo ${FOO%/*} # 後方の /* を削ります。(最短のマッチ) foo/bar $ echo ${FOO%%/*} # 後方の /* を削ります。(最長のマッチ) foo $ echo ${FOO#foobar} # マッチしない場合はそのまま foo/bar/baz パスのディレクトリ部分やファイル名部分を取り出すときに、 `dirname` コマンドや `basename` コマンド を使わなくても、`${FOO%/*}` と `${FOO##*/}` で代用できるということですね。 ここから先は、bash でしか使えない書き方です。 これらをスクリプトで使うときは、shebang を `#!/bin/bash` にすること。 - `${variable^}` `variable` の値の 1文字目を大文字に変換する。 - `${variable^^}` `variable` の値の 全文字を大文字に変換する。 - `${variable,}` `variable` の値の 1文字目を小文字に変換する。 - `${variable,,}` `variable` の値の 全文字を小文字に変換する。 - `${variable~}` `variable` の値の 1文字目を大文字小文字反転。 - `${variable~~}` `variable` の値の 全文字を大文字小文字反転。 - `${variable/before/after/}` `variable` の値で、`before` にマッチした文字列を `after` に置換する。(最初にマッチしたもののみ)
`echo $variable | sed s/before/after/` の動作。 - `${variable//before/after/}` `variable` の値で、`before` にマッチした文字列を `after` に置換する。(マッチしたものすべて置換)
`echo $variable | sed s/before/after/g` の動作。
前の投稿
ホーム
登録:
投稿 (Atom)