シェルスクリプト総合 その20
■ このスレッドは過去ログ倉庫に格納されています
0001名無しさん@お腹いっぱい。
2012/06/08(金) 00:35:51.19スクリプトのお勉強・自慢・腕試しなどにどうぞ。
□お約束
・特記なき場合はBourne Shell(/bin/sh)がデフォルトです。
bash/zsh/ksh/ashなどに依存する場合は明示しましょう。
Linuxユーザは/bin/shの正体がbashなので特に注意。
FreeBSDユーザは/bin/shの正体がashなので注意。
v7 shに一番近くて、現役のshは、OpenSolaris由来のheirloom sh。
http://src.opensolaris.org/source/xref/onnv/onnv-gate/usr/src/cmd/sh/
http://heirloom.sourceforge.net/sh.html
・csh/tcshのシェルスクリプトは推奨されません。
(理由は「csh-whynot」でググれ)
・UNIXにはシェルスクリプトに便利な小さなコマンドがいろいろあります。
manや参考リンクを見ましょう。
aproposないしはman -kでそれらしい単語による簡単な検索もできます。
・シェルスクリプトのことをシェルってゆーな
・シェルで使えるワイルドカード等は正規表現ではありません。
正規表現の話題はスレ違い(正規表現スレへ)
□初心者へのアドバイス:
・適した道具を判断するのも頭の重要な使い方。シェルスクリプトよりも
RubyやPerlの方が適した仕事には素直にそちらを使いましょう。
・知らないコマンドが出てきたらmanを引きましょう。
・思い通りに動かないときは、まずは sh -x でトレースしましょう。
前スレ
シェルスクリプト総合 その19
http://toro.2ch.net/test/read.cgi/unix/1323515200/
0486名無しさん@お腹いっぱい。
2012/07/30(月) 11:54:55.78やだなあ。レス番よく追ってよ。僕(>>477)は、3つのシェルの仕様のANDを
取ってる自称プロを弄ってた方だよ。
0487名無しさん@お腹いっぱい。
2012/07/30(月) 12:02:20.94まあ >>477 の主張はちょっと不明確な気がする。
4つのシェルの仕様のANDとって、空集合になるなんてことはあまりない
(だいたいは代替手段がある)ので、何が言いたいのか分からないな。
4つのシェルの仕様をちゃんと読めば、目的が果たせることには変わりない。
問題なのは、それがとんでもない時間の無駄使いだってことだろう。
0488名無しさん@お腹いっぱい。
2012/07/30(月) 12:02:51.87または
バックスラッシュが使われている場合が implementation-defined
と書かれている。
実はこれダウトなんだよ。
bashやzshのechoとか、-E (大文字)も特別扱いするから、(-eもだけど)
echo -E は、POSIXで言うところのimplementation-definedに該当しないはずなのに
ポータビリティーがない。
-E -e の件はPOSIX読んだだけでは書かれていないから、
正確なことを知るには自分でAND取るしかない。
0489名無しさん@お腹いっぱい。
2012/07/30(月) 12:08:03.50でも、自称プロは自分でANDを取る。 w
延べ数千人のレビューを経たPOSIXより、自分でANDを取った規約の方が上。
0490名無しさん@お腹いっぱい。
2012/07/30(月) 12:11:17.53延べ数千人のレビューを得ても echo -E / echo -e を見落としたんですか?
0491名無しさん@お腹いっぱい。
2012/07/30(月) 12:18:41.90> 正確なことを知るには自分でAND取るしかない。
お、珍しくマトモな意見だな。
POSIX の仕様が -n に限ってるのは、BSD の仕様をベースにしてるからだな。
だから *BSD で /bin/sh 使う分には POSIX だけで OK だけど、bash や zsh
だとまずい。
実際、俺は - で始まる文字列は単に避けるか、どうしても必要な場合は
printf 使うようにしてるんだよね。
規格は基本、実装の後追いだから、Linux 起源の仕様がどんどん POSIX に
採り入れられている現状からして、そのうち、echo の仕様も訂正されるん
じゃないかな。(でも getline(3) みたいなウンコはやめて欲しかったがなorz)
こういう齟齬は避けられないから、テストは不可欠だし、できれば各シェルの
マニュアルも確認しておいた方がいい。
でも、順番としてはまず POSIX が最初で、各シェルのマニュアルを参照するのは
後だよ。こういう例外を除き、ほとんどの場合、POSIX が仕様の AND をとっていて
くれるので、その方がずっと効率がいいからな。
だから、「各シェルのマニュアルも読んだ方がいいよ」って言うのなら主張として
いいんだよ。だが「POSIX は要らん。各シェルのマニュアルのANDだけで良い」と
いう主張はおかしい。まず最初に POSIX を確認すべき。
「各シェルのマニュアルのAND」は最後でいい。テストでコケるまで参照しなくても
いいくらいに優先順位が低い。
0492名無しさん@お腹いっぱい。
2012/07/30(月) 13:58:58.260493名無しさん@お腹いっぱい。
2012/07/30(月) 14:03:07.82それに Debian GNU/Linux があるぜ。
まあ FreeBSD だけに限っても無理だろうけど。
0494名無しさん@お腹いっぱい。
2012/07/30(月) 22:42:54.260495名無しさん@お腹いっぱい。
2012/07/30(月) 23:13:07.540496名無しさん@お腹いっぱい。
2012/07/31(火) 00:37:56.280497名無しさん@お腹いっぱい。
2012/07/31(火) 00:57:04.92ANDとる作業で工数水増ししてるのかもね。w
0498名無しさん@お腹いっぱい。
2012/07/31(火) 01:04:07.56""rm
という記述を見たんですが、""ってなんか意味があるんでしょうか?
0499名無しさん@お腹いっぱい。
2012/07/31(火) 02:14:35.410500名無しさん@お腹いっぱい。
2012/07/31(火) 06:30:16.070501名無しさん@お腹いっぱい。
2012/07/31(火) 12:35:16.71だからだろ
0502名無しさん@お腹いっぱい。
2012/07/31(火) 12:46:26.030503名無しさん@お腹いっぱい。
2012/07/31(火) 14:19:59.11なんか重い処理を並列で走らせるときに
cmd1 &
cmd2 &
cmd3 &
wait
みたいな感じで。
0504名無しさん@お腹いっぱい。
2012/07/31(火) 14:34:56.99それジョブコントロールちゃう。ただのバックグラウンド。
SIGTSTPで止めてバックに回して、
あとで fgしたりするやつ。
0505名無しさん@お腹いっぱい。
2012/07/31(火) 15:01:13.63節子、を付けるべきだなw
0506名無しさん@お腹いっぱい。
2012/07/31(火) 15:07:12.600507名無しさん@お腹いっぱい。
2012/07/31(火) 15:16:47.63ちがう。
決定的な違いはプロセスグループIDの処理。
ジョブコントロールの場合は各コマンドのプロセスグループIDを別々にして、
親のシェルからは独立する。ttyの端末プロセスグループIDを
フォアグラウンドプロセスと同一にし、管理を行なう。
一方、ジョブコントロールなしの場合は、fork/execのあと、
単にwaitしないというだけの処理で、プロセスグループIDは親シェルと同じ。
だから、Ctrl-Cで同一プロセスグループIDのプロセスが死なないように
&を付けたコマンドはSIGINTを無視するようにしている。
(ジョブコントロール有りの場合はSIGINTはそのまま無視しない)
ジョブコントロールは、今のシェルなら set +m で無効にできる。
set +m でジョブコントロール無効にした状態でも
& や waitは実行できる。
純正/bin/shにはジョブコントロールがなかったが、
& や waitは当然実行できる。
0508名無しさん@お腹いっぱい。
2012/07/31(火) 15:31:33.28それって\の方がシンプルだよね?
0509名無しさん@お腹いっぱい。
2012/08/01(水) 22:19:00.88if [ -z "$MNT" ]; then
mount -t proc proc ../rootfs/proc/
fi
この構文は短縮できないんでしょうか
0510名無しさん@お腹いっぱい。
2012/08/01(水) 22:22:35.02mount | grep -q 'rootfs/proc' && mount -t proc proc ../rootfs/proc
0511510
2012/08/01(水) 22:23:46.64|| に。
0513名無しさん@お腹いっぱい。
2012/08/02(木) 08:59:36.06mount -t proc proc ../rootfs/proc/ >/dev/null 2>&1 || :
でいいじゃね?
0514名無しさん@お腹いっぱい。
2012/08/02(木) 09:25:31.26mount -t proc proc ../rootfs/proc/ >/dev/null 2>&1; :
でいいじゃね?
0515名無しさん@お腹いっぱい。
2012/08/02(木) 09:28:56.050516名無しさん@お腹いっぱい。
2012/08/02(木) 20:18:32.37command hoge $@
}
という関数を定義してたんですが
jikken -m "" -n "" unko
というコマンドを実行すると
hoge -m -n unko
というコマンドの実行になってしまうんですよね。
引数をきっちり hoge に渡すには
どうしたらいいんですかね
0517名無しさん@お腹いっぱい。
2012/08/02(木) 20:24:44.260518名無しさん@お腹いっぱい。
2012/08/02(木) 20:29:19.70ありがとう
0519名無しさん@お腹いっぱい。
2012/08/08(水) 12:58:57.06同じことを bash の拡張機能を使わず、かつ内部コマンドだけでやる方法ってないかな?
いまは echo $a | cut -c$x-$y でやってるけど、
スクリプト中で何百回と呼ばれていて、これのせいでかなり速度が遅くなっちゃってる。
0520名無しさん@お腹いっぱい。
2012/08/08(水) 13:18:46.05頭の3文字と後ろの2文字をカットしたい場合、
a=ABCDEFG
b=${a#???}
echo "${b%??}"
みたいにするしかないかな。この例では DE が残る。
0521名無しさん@お腹いっぱい。
2012/08/08(水) 14:17:12.55? を指定回数数並べた文字列を作るのにまためんどくさい手間がかかるのはちょっと。
とはいえ、やっぱり方法はそれしかないよなぁ。
0522名無しさん@お腹いっぱい。
2012/08/08(水) 14:18:52.44printf %.5s '??????????????'
で5個の ????? が得られるよ。
0523名無しさん@お腹いっぱい。
2012/08/08(水) 14:20:25.24printf "%.*s" 5 '?????????????????????????????'
0524名無しさん@お腹いっぱい。
2012/08/08(水) 14:24:59.78>>522 で合ってる。 %.${a}s にすればいいだけ
0525名無しさん@お腹いっぱい。
2012/08/08(水) 14:35:28.320526名無しさん@お腹いっぱい。
2012/08/08(水) 15:49:08.270527名無しさん@お腹いっぱい。
2012/08/08(水) 21:33:50.42一時ファイルの代わりにこれを使えばHDDガリガリしなくて済むんだよね?
0528名無しさん@お腹いっぱい。
2012/08/09(木) 00:33:59.19diff -u <(ls /old) <(ls /new)
とかできるから、わざわざ名前つけたりは、ほとんどしなくなったなあ。
0529名無しさん@お腹いっぱい。
2012/08/09(木) 06:48:33.30(mkfifoのことじゃなくて)
0530名無しさん@お腹いっぱい。
2012/08/09(木) 10:01:01.43それはないと思いたいところだけどなあ。どうだろね。
0531名無しさん@お腹いっぱい。
2012/08/09(木) 10:45:19.41実装依存だな。(言葉の誤用ではない)
FreeBSDだと本当にnamed pipeで実装されてるよ。
bash$ file <(:)
/tmp/sh-np-4033202023: fifo (named pipe)
0532名無しさん@お腹いっぱい。
2012/08/09(木) 10:57:37.18どうやってnamed pipe以外で実装するんだよ。
0533名無しさん@お腹いっぱい。
2012/08/09(木) 10:59:51.72Linuxだと、普通のpipeで実装して、それを/dev/fd/n(/proc/self/fd/n)経由で参照する 。
だからnamed pipeにする必要はない。
0534名無しさん@お腹いっぱい。
2012/08/09(木) 11:09:46.250535名無しさん@お腹いっぱい。
2012/08/09(木) 11:47:08.570536名無しさん@お腹いっぱい。
2012/08/09(木) 11:49:03.21いや、実装依存だから、名前の誤用なんだよ。
「<(コマンド)」の実装に常に named pipe が必要ならばともかく、
pipe(2) で実装されたり named pipe で実装されたりするものを、
named pipe って呼んじゃ駄目でしょ。
0537名無しさん@お腹いっぱい。
2012/08/09(木) 11:50:51.69「<(コマンド)」の場合なら、これを解釈するシェルが始末する。
自力で named pipe 作ってるシェルスクリプトなら、ふつうは
そのスクリプトの中で trap とか使ってやるんじゃない?
(named pipe の目的にもよるので状況によりけりだけど)
0538名無しさん@お腹いっぱい。
2012/08/09(木) 12:06:58.48もともと「named pipeを自動で」という設計思想で設計されたものだから、
結果の実装がどうあれ、named pipeと呼んで良い。
0539名無しさん@お腹いっぱい。
2012/08/09(木) 12:13:15.060540名無しさん@お腹いっぱい。
2012/08/09(木) 12:23:57.330541名無しさん@お腹いっぱい。
2012/08/09(木) 12:31:51.13こんなのとか
daemon hoge <(hage)
0542名無しさん@お腹いっぱい。
2012/08/09(木) 13:19:33.96え、そんなの初めて聞いたぞ。
「"named pipe" "shell script"」でググって出てくる上位5サイトに
「<(コマンド)」や「>(コマンド)」の話が、チラっとも出てこない
ことからして、君の組織だけで生まれたローカルな用法なんじゃねえ?
0543名無しさん@お腹いっぱい。
2012/08/09(木) 13:32:16.610544名無しさん@お腹いっぱい。
2012/08/09(木) 13:35:52.740545名無しさん@お腹いっぱい。
2012/08/09(木) 13:40:06.410546名無しさん@お腹いっぱい。
2012/08/09(木) 13:40:10.34UNIX domain socketでは、そのファイル名を渡されたコマンド側が
open()でオープンできないから無理。
0547名無しさん@お腹いっぱい。
2012/08/09(木) 13:41:12.87openできないからだめ。
0548名無しさん@お腹いっぱい。
2012/08/09(木) 14:21:53.82「コマンド置換」と、
「名前つきパイプ または ファイル・ディスクリプターの /dev/fd 形式での指定」が、
きちんと分離して書かれてるね。
しかも、名前つきパイプが使えることと、コマンド置換が使えることは等価ではない
(ファイル・ディスクリプターの /dev/fd 形式での指定ができればコマンド置換が
使える)ことも明確に書かれている。
ますます >>538 が、何を読んで、コマンド置換のことを名前つきパイプだと
思い込んだのか知りたくなるな。まさか >>543 の文章じゃないよな。
0549548
2012/08/09(木) 14:26:25.67だった。
0550名無しさん@お腹いっぱい。
2012/08/09(木) 14:26:36.710551名無しさん@お腹いっぱい。
2012/08/09(木) 14:27:37.29「コマンド置換」??www
いつの間にコマンド置換に話になったんだよw
プロセス置換を理解していない無知自慢かよwww
0552名無しさん@お腹いっぱい。
2012/08/09(木) 15:34:32.97/dev/shmに一時ファイル作ってガリガリ言わんようにしてたな
他に何も代わりの方法を思いつかなかったからだが
パイプって読取る方が書込む方より遅かった場合、書込む方は待たされるのか?
最近マルチコアが当たり前だし、キャッシュも利くだろうから、
一時ファイル作る方が速く処理が終わるかもしれん
0553名無しさん@お腹いっぱい。
2012/08/09(木) 15:52:20.68> パイプって読取る方が書込む方より遅かった場合、書込む方は待たされるのか?
でかい出力処理 | less
とかやったことないの?
> 最近マルチコアが当たり前
と
> 一時ファイル作る方が速く
が、全然つながんねえ
0554名無しさん@お腹いっぱい。
2012/08/09(木) 15:56:31.53> と
> > 一時ファイル作る方が速く
> が、全然つながんねえ
だね。
名前つき/なしに関わらず、パイプやソケットならマルチコアで
並列に動く可能性がある(マルチコアを生かせる)けど、
ファイル経由してたら、シングルコアと性能変わらん。
>>551
で、結局、「プロセス置換のことを、named pipe と呼ぶ」っていうのは
どこかの組織のローカルルールの話だったってことで OK?
世の中に広まってる話なら、ソースよろ
0555名無しさん@お腹いっぱい。
2012/08/09(木) 16:12:16.26ggrks
0556名無しさん@お腹いっぱい。
2012/08/09(木) 16:17:46.74たぶんzshでしか動きません:)
command-line clock - Pastebin.com
http://pastebin.com/HvYxU9bu
>>read -t1 q ## -t1=timeout option 1 second.
ところで、ここを-t0.001とかどんどん小さな値にしていくと、終了時の動作(適当にEnterとか入力して終わらせてください。)として
breakした後にまだechoってるような表示になってまうことが10回起動・終了すれば1回ぐらいあるような感じなんですが、
これってなんでなんですか。
0557名無しさん@お腹いっぱい。
2012/08/09(木) 16:26:30.18sleep 0.5
とか入れてみればほぼ100%再現するよ
0558名無しさん@お腹いっぱい。
2012/08/09(木) 16:28:06.39答えられないのね。
0559名無しさん@お腹いっぱい。
2012/08/09(木) 16:29:35.46うん、そうなんですよね。どういうことなんでしょうか。
ていうか、プログラムのコピペミスってますね、さーせん。
0560名無しさん@お腹いっぱい。
2012/08/09(木) 16:33:00.69本当にありがとうございました。
0561名無しさん@お腹いっぱい。
2012/08/09(木) 16:36:14.11グーグルは存在の検索はできるが、非存在の検索は出来ない。
0562名無しさん@お腹いっぱい。
2012/08/09(木) 16:36:26.28readの変数への代入がwhileループ始まるより遅いってこと?
0563名無しさん@お腹いっぱい。
2012/08/09(木) 16:38:02.93本当にありがとうございました。
0564名無しさん@お腹いっぱい。
2012/08/09(木) 16:38:42.420565名無しさん@お腹いっぱい。
2012/08/09(木) 16:39:14.15変数への代入じゃなくて、
read実行開始時に端末のバッファをフラッシュする関係で
直前のEnterを取りこぼすということ。
0566名無しさん@お腹いっぱい。
2012/08/09(木) 16:42:25.90いや、それは違うだろ
0567名無しさん@お腹いっぱい。
2012/08/09(木) 16:45:15.730568名無しさん@お腹いっぱい。
2012/08/09(木) 16:47:58.63性能評価のレポートによりpipeで渡す方が効率が良いということになった。
もちろんSSDが主流になるといろいろと変わってくると思われるが。
0569名無しさん@お腹いっぱい。
2012/08/09(木) 16:49:47.73まあどっちも POSIX 外で、移植性はないけどな。
0570名無しさん@お腹いっぱい。
2012/08/09(木) 16:52:50.820571名無しさん@お腹いっぱい。
2012/08/09(木) 16:55:46.680572名無しさん@お腹いっぱい。
2012/08/09(木) 17:02:39.79sleep 0.5 は *BSD で可なので、Linux限定ではない
read -t は zsh で可なので、Linux限定ではない
0573556
2012/08/09(木) 17:18:27.14While文の条件判定の所で一番時間が掛かるようになっていって、
そこの間でEnterを打ち込むから、echoが二度効いてしまうように見えるってことかな?
最初はecho中にEnterが効いてるからと思ったけど、それならWhileループに二度目突入しないものね。
0574名無しさん@お腹いっぱい。
2012/08/09(木) 17:25:58.46echoの最初の文字を出力する瞬間までの、どこでもありうるね
echoが二度効いてるんじゃなくて、Enterで次の行に行っちゃったから、
そこにechoしてるだけ。
0575名無しさん@お腹いっぱい。
2012/08/09(木) 17:58:01.770576名無しさん@お腹いっぱい。
2012/08/09(木) 18:20:53.390577名無しさん@お腹いっぱい。
2012/08/09(木) 18:38:20.10所で、時計なのに一定時間待つって処理でいいの?タイマ設定してシグナル送ってもらった方が正確じゃね
0578556
2012/08/09(木) 18:59:37.13http://pastebin.com/nRfEbSZF
ちょっと改変して、コマンドのreturnの値を条件式として使うように、
こんな風にしてみました。
でも、こうしても-tの値を減少させていくと、二重にechoってるようになるのが
どうしても解せません。なんでだよ!さすがにおかしいだろ!
やっぱり順次処理されてないのでは?
>>577
そんな格好いいのが出来るなら、敗北は認めなければなりませんね。
そこに美しさがあれば世界金メダルは譲ります。
0579名無しさん@お腹いっぱい。
2012/08/09(木) 19:02:59.50そこでEnter打ったらなるんだよ
echoの前に sleep 入れてみたら確認できるだろ
0580556
2012/08/09(木) 19:06:32.81あ、前のechoが残ってるのか、
どうやらオバカさん世界一の金メダルは私のもののようですね。ふっふっふっ。
本当にどうもありがとうございました。
0581名無しさん@お腹いっぱい。
2012/08/09(木) 19:18:48.76BSD&Linux の拡張 sleep とかに依存せず、POSIX 範囲内で書けないか?
こんな感じ。
#!/bin/sh
while :; do printf "\r%s" "$(date +%Y-%m-%dT%H:%M:%S%:z)"; sleep 1; done &
pid=$!
read x
kill $pid
0582名無しさん@お腹いっぱい。
2012/08/09(木) 19:25:37.741秒未満でもうちょっと細かく再表示したいっていう意図じゃないの?
0583名無しさん@お腹いっぱい。
2012/08/09(木) 19:26:03.35せっかくそこまでするなら $( ) は ` ` にすべき。
0584名無しさん@お腹いっぱい。
2012/08/09(木) 19:35:13.63> 1秒未満でもうちょっと細かく再表示したいっていう意図じゃないの?
対話的シェルにリアルタイム保証なんてないから、read -t の時刻指定を
いくら細かくしたところで、マシン負荷が高くなれば、2秒どころかもっと
進む可能性はあるよ。そういう、対話的シェルで実現困難な仕様は、そもそも
盛り込むべきじゃないだろう。
ちょっとの負荷で2秒とびが嫌だっていうなら、拡張sleepに依存して
sleep 1 を sleep 0.9 ぐらいにするって手は、まあないわけではない。
read -t や sleep で指定する秒数をあまり小さくすると、無駄なマシン負荷が
増えるので、あまり小さくするのは推奨せんが。
>>583
Solaris の古いシェルとかで動かすことも考慮するなら、その通りだな。
まあ、そこは常識で分かると判断した。
0585名無しさん@お腹いっぱい。
2012/08/09(木) 19:36:24.680586名無しさん@お腹いっぱい。
2012/08/09(木) 19:39:33.95それを sleep 0.123 とかの小数点以下に(計算の上)反映すれば
無駄にプロセスを使わずにうまく同期できるのでは?
■ このスレッドは過去ログ倉庫に格納されています