トップページunix
1001コメント289KB

シェルスクリプト総合 その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/
0504名無しさん@お腹いっぱい。2012/07/31(火) 14:34:56.99
>>503
それジョブコントロールちゃう。ただのバックグラウンド。

SIGTSTPで止めてバックに回して、
あとで fgしたりするやつ。
0505名無しさん@お腹いっぱい。2012/07/31(火) 15:01:13.63
>>504
節子、を付けるべきだなw
0506名無しさん@お腹いっぱい。2012/07/31(火) 15:07:12.60
バックグラウンドで動かすのもジョブコントロールの一部でしょ。
0507名無しさん@お腹いっぱい。2012/07/31(火) 15:16:47.63
>>506
ちがう。

決定的な違いはプロセスグループ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
>>499
それって\の方がシンプルだよね?
0509名無しさん@お腹いっぱい。2012/08/01(水) 22:19:00.88
MNT=$(mount | grep "rootfs/proc")
if [ -z "$MNT" ]; then
mount -t proc proc ../rootfs/proc/
fi
この構文は短縮できないんでしょうか
0510名無しさん@お腹いっぱい。2012/08/01(水) 22:22:35.02
>>509
mount | grep -q 'rootfs/proc' && mount -t proc proc ../rootfs/proc
05115102012/08/01(水) 22:23:46.64
&&ではなく、
|| に。
05125092012/08/01(水) 22:32:13.39
>>510
ははあー
0513名無しさん@お腹いっぱい。2012/08/02(木) 08:59:36.06
いちいち判定しなくても二重にマウントされることはないんだから、
mount -t proc proc ../rootfs/proc/ >/dev/null 2>&1 || :
でいいじゃね?
0514名無しさん@お腹いっぱい。2012/08/02(木) 09:25:31.26
いちいち||判定しなくても最後のステータスが有効なんだから、
mount -t proc proc ../rootfs/proc/ >/dev/null 2>&1; :
でいいじゃね?
0515名無しさん@お腹いっぱい。2012/08/02(木) 09:28:56.05
書き込んだらセミコロン(;)消えた、、まあ、set -eなんてしてないという前提で。
0516名無しさん@お腹いっぱい。2012/08/02(木) 20:18:32.37
jikken () {
command hoge $@
}
という関数を定義してたんですが

jikken -m "" -n "" unko

というコマンドを実行すると
hoge -m -n unko
というコマンドの実行になってしまうんですよね。
引数をきっちり hoge に渡すには
どうしたらいいんですかね
0517名無しさん@お腹いっぱい。2012/08/02(木) 20:24:44.26
command hoge "$@"
0518名無しさん@お腹いっぱい。2012/08/02(木) 20:29:19.70
>>517
ありがとう
0519名無しさん@お腹いっぱい。2012/08/08(水) 12:58:57.06
bash だと変数の部分文字列を ${a:m:n} で取得できるけど、
同じことを bash の拡張機能を使わず、かつ内部コマンドだけでやる方法ってないかな?

いまは echo $a | cut -c$x-$y でやってるけど、
スクリプト中で何百回と呼ばれていて、これのせいでかなり速度が遅くなっちゃってる。
0520名無しさん@お腹いっぱい。2012/08/08(水) 13:18:46.05
>>519
頭の3文字と後ろの2文字をカットしたい場合、

a=ABCDEFG
b=${a#???}
echo "${b%??}"

みたいにするしかないかな。この例では DE が残る。
0521名無しさん@お腹いっぱい。2012/08/08(水) 14:17:12.55
ありがとう。それは考えたんだけど、位置を数値指定したいんだよね。
? を指定回数数並べた文字列を作るのにまためんどくさい手間がかかるのはちょっと。

とはいえ、やっぱり方法はそれしかないよなぁ。
0522名無しさん@お腹いっぱい。2012/08/08(水) 14:18:52.44
>>521
printf %.5s '??????????????'

で5個の ????? が得られるよ。
0523名無しさん@お腹いっぱい。2012/08/08(水) 14:20:25.24
欲しいのはこっちだろ
printf "%.*s" 5 '?????????????????????????????'
0524名無しさん@お腹いっぱい。2012/08/08(水) 14:24:59.78
>>523
>>522 で合ってる。 %.${a}s にすればいいだけ
0525名無しさん@お腹いっぱい。2012/08/08(水) 14:35:28.32
おお、ありがとです。なんとかなりそうだ。
0526名無しさん@お腹いっぱい。2012/08/08(水) 15:49:08.27
実行速度が3倍になった。ありがとう。
0527名無しさん@お腹いっぱい。2012/08/08(水) 21:33:50.42
名前付きパイプの使い方を修得した (`・ω・´)

一時ファイルの代わりにこれを使えばHDDガリガリしなくて済むんだよね?
0528名無しさん@お腹いっぱい。2012/08/09(木) 00:33:59.19
まあその通りだが、いまのシェルだと
diff -u <(ls /old) <(ls /new)
とかできるから、わざわざ名前つけたりは、ほとんどしなくなったなあ。
0529名無しさん@お腹いっぱい。2012/08/09(木) 06:48:33.30
>>528 のことを「名前付きパイプ」って呼んでる可能性もあるわけで・・
(mkfifoのことじゃなくて)
0530名無しさん@お腹いっぱい。2012/08/09(木) 10:01:01.43
そうだとすると言葉の誤用なので (実装は pipe(2)でできるし)、
それはないと思いたいところだけどなあ。どうだろね。
0531名無しさん@お腹いっぱい。2012/08/09(木) 10:45:19.41
>>530
実装依存だな。(言葉の誤用ではない)
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.72
>>532
Linuxだと、普通のpipeで実装して、それを/dev/fd/n(/proc/self/fd/n)経由で参照する 。
だからnamed pipeにする必要はない。
0534名無しさん@お腹いっぱい。2012/08/09(木) 11:09:46.25
Named pipeの後始末は誰がする?
0535名無しさん@お腹いっぱい。2012/08/09(木) 11:47:08.57
私自らが処罰を与える
0536名無しさん@お腹いっぱい。2012/08/09(木) 11:49:03.21
>>531
いや、実装依存だから、名前の誤用なんだよ。
「<(コマンド)」の実装に常に named pipe が必要ならばともかく、
pipe(2) で実装されたり named pipe で実装されたりするものを、
named pipe って呼んじゃ駄目でしょ。
0537名無しさん@お腹いっぱい。2012/08/09(木) 11:50:51.69
>>534
「<(コマンド)」の場合なら、これを解釈するシェルが始末する。

自力で named pipe 作ってるシェルスクリプトなら、ふつうは
そのスクリプトの中で trap とか使ってやるんじゃない?
(named pipe の目的にもよるので状況によりけりだけど)
0538名無しさん@お腹いっぱい。2012/08/09(木) 12:06:58.48
>>536
もともと「named pipeを自動で」という設計思想で設計されたものだから、
結果の実装がどうあれ、named pipeと呼んで良い。
0539名無しさん@お腹いっぱい。2012/08/09(木) 12:13:15.06
>>527がおいてけぼりになっとる。
0540名無しさん@お腹いっぱい。2012/08/09(木) 12:23:57.33
上の例だとdiff終了時点でshellが削除だろうね。
0541名無しさん@お腹いっぱい。2012/08/09(木) 12:31:51.13
全子孫が終了するまで削除しちゃだめだよね。

こんなのとか
daemon hoge <(hage)
0542名無しさん@お腹いっぱい。2012/08/09(木) 13:19:33.96
>>538
え、そんなの初めて聞いたぞ。

「"named pipe" "shell script"」でググって出てくる上位5サイトに
「<(コマンド)」や「>(コマンド)」の話が、チラっとも出てこない
ことからして、君の組織だけで生まれたローカルな用法なんじゃねえ?
0543名無しさん@お腹いっぱい。2012/08/09(木) 13:32:16.61
プロセス置換 (process substitution) がサポートされるのは、 名前付きパイプ (FIFO) または ファイル・ディスクリプターの /dev/fd 形式での指定 をサポートしているシステムです。
0544名無しさん@お腹いっぱい。2012/08/09(木) 13:35:52.74
UNIX domain socketでも何とかなるでしょ。
0545名無しさん@お腹いっぱい。2012/08/09(木) 13:40:06.41
>>543はbashのman page
0546名無しさん@お腹いっぱい。2012/08/09(木) 13:40:10.34
>>544
UNIX domain socketでは、そのファイル名を渡されたコマンド側が
open()でオープンできないから無理。
0547名無しさん@お腹いっぱい。2012/08/09(木) 13:41:12.87
>>544
openできないからだめ。
0548名無しさん@お腹いっぱい。2012/08/09(木) 14:21:53.82
>>543
「コマンド置換」と、
「名前つきパイプ または ファイル・ディスクリプターの /dev/fd 形式での指定」が、
きちんと分離して書かれてるね。

しかも、名前つきパイプが使えることと、コマンド置換が使えることは等価ではない
(ファイル・ディスクリプターの /dev/fd 形式での指定ができればコマンド置換が
使える)ことも明確に書かれている。

ますます >>538 が、何を読んで、コマンド置換のことを名前つきパイプだと
思い込んだのか知りたくなるな。まさか >>543 の文章じゃないよな。
05495482012/08/09(木) 14:26:25.67
s/コマンド置換/プロセス置換/
だった。
0550名無しさん@お腹いっぱい。2012/08/09(木) 14:26:36.71
初期のshellは”コマンド置換”的な文法だったと「UNIX原典」にあった。
0551名無しさん@お腹いっぱい。2012/08/09(木) 14:27:37.29
>>548
「コマンド置換」??www

いつの間にコマンド置換に話になったんだよw

プロセス置換を理解していない無知自慢かよwww
0552名無しさん@お腹いっぱい。2012/08/09(木) 15:34:32.97
<( … )の形でパイプが使えると知らなかったときは
/dev/shmに一時ファイル作ってガリガリ言わんようにしてたな
他に何も代わりの方法を思いつかなかったからだが

パイプって読取る方が書込む方より遅かった場合、書込む方は待たされるのか?
最近マルチコアが当たり前だし、キャッシュも利くだろうから、
一時ファイル作る方が速く処理が終わるかもしれん
0553名無しさん@お腹いっぱい。2012/08/09(木) 15:52:20.68
>>552
> パイプって読取る方が書込む方より遅かった場合、書込む方は待たされるのか?
でかい出力処理 | less
とかやったことないの?

> 最近マルチコアが当たり前

> 一時ファイル作る方が速く
が、全然つながんねえ
0554名無しさん@お腹いっぱい。2012/08/09(木) 15:56:31.53
> > 最近マルチコアが当たり前
> と
> > 一時ファイル作る方が速く
> が、全然つながんねえ

だね。
名前つき/なしに関わらず、パイプやソケットならマルチコアで
並列に動く可能性がある(マルチコアを生かせる)けど、
ファイル経由してたら、シングルコアと性能変わらん。

>>551
で、結局、「プロセス置換のことを、named pipe と呼ぶ」っていうのは
どこかの組織のローカルルールの話だったってことで OK?
世の中に広まってる話なら、ソースよろ

0555名無しさん@お腹いっぱい。2012/08/09(木) 16:12:16.26
>>554
ggrks
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.18
readの次に
sleep 0.5
とか入れてみればほぼ100%再現するよ
0558名無しさん@お腹いっぱい。2012/08/09(木) 16:28:06.39
>>555
答えられないのね。
0559名無しさん@お腹いっぱい。2012/08/09(木) 16:29:35.46
>>557
うん、そうなんですよね。どういうことなんでしょうか。
ていうか、プログラムのコピペミスってますね、さーせん。
0560名無しさん@お腹いっぱい。2012/08/09(木) 16:33:00.69
あぁ、sleep中に打ち込んでるからってことでしょうか。なるほろ×2。
本当にありがとうございました。
0561名無しさん@お腹いっぱい。2012/08/09(木) 16:36:14.11
>>555
グーグルは存在の検索はできるが、非存在の検索は出来ない。
0562名無しさん@お腹いっぱい。2012/08/09(木) 16:36:26.28
いや、でもやっぱりそれっておかしくねえ?
readの変数への代入がwhileループ始まるより遅いってこと?
0563名無しさん@お腹いっぱい。2012/08/09(木) 16:38:02.93
あぁ、おかしくないか、打ちこんでる間のタイムアウトの方が早くて次のループに入ってるだけの話か。そういうことっすよね?
本当にありがとうございました。
0564名無しさん@お腹いっぱい。2012/08/09(木) 16:38:42.42
改行して、whileで一度中に入って、時刻表示して、次のreadで取り込まれて、while抜ける
0565名無しさん@お腹いっぱい。2012/08/09(木) 16:39:14.15
>>562
変数への代入じゃなくて、
read実行開始時に端末のバッファをフラッシュする関係で
直前のEnterを取りこぼすということ。
0566名無しさん@お腹いっぱい。2012/08/09(木) 16:42:25.90
>>565
いや、それは違うだろ
0567名無しさん@お腹いっぱい。2012/08/09(木) 16:45:15.73
read -t 0.01 とか sleep 0.5 とか、Linux限定全開ですな
0568名無しさん@お腹いっぱい。2012/08/09(木) 16:47:58.63
昔gccがgasにpipeで渡すか、それとも一時ファイルかという議論があった時は、
性能評価のレポートによりpipeで渡す方が効率が良いということになった。
もちろんSSDが主流になるといろいろと変わってくると思われるが。
0569名無しさん@お腹いっぱい。2012/08/09(木) 16:49:47.73
read -t は駄目だけど、sleep 0.5 は *BSD でも動くよ。
まあどっちも POSIX 外で、移植性はないけどな。
0570名無しさん@お腹いっぱい。2012/08/09(木) 16:52:50.82
zsh限定って最初から断わってんだから、read -t も有り
0571名無しさん@お腹いっぱい。2012/08/09(木) 16:55:46.68
sleepってビルトイン関数じゃないからzsh関係ないような。
0572名無しさん@お腹いっぱい。2012/08/09(木) 17:02:39.79
だからー
sleep 0.5 は *BSD で可なので、Linux限定ではない
read -t は zsh で可なので、Linux限定ではない
05735562012/08/09(木) 17:18:27.14
-tの時間を少なくしていくと、
While文の条件判定の所で一番時間が掛かるようになっていって、
そこの間でEnterを打ち込むから、echoが二度効いてしまうように見えるってことかな?

最初はecho中にEnterが効いてるからと思ったけど、それならWhileループに二度目突入しないものね。
0574名無しさん@お腹いっぱい。2012/08/09(木) 17:25:58.46
readがタイムアウトした瞬間から、
echoの最初の文字を出力する瞬間までの、どこでもありうるね
echoが二度効いてるんじゃなくて、Enterで次の行に行っちゃったから、
そこにechoしてるだけ。
0575名無しさん@お腹いっぱい。2012/08/09(木) 17:58:01.77
世界最強ってところには誰も突っこまないのか。
0576名無しさん@お腹いっぱい。2012/08/09(木) 18:20:53.39
そこつっこんでも面白くならない。
0577名無しさん@お腹いっぱい。2012/08/09(木) 18:38:20.10
突っ込まれたくないなら世界で2番目くらいに強いって言っとけばいい

所で、時計なのに一定時間待つって処理でいいの?タイマ設定してシグナル送ってもらった方が正確じゃね
05785562012/08/09(木) 18:59:37.13
command-line clock v2 - Pastebin.com
http://pastebin.com/nRfEbSZF

ちょっと改変して、コマンドのreturnの値を条件式として使うように、
こんな風にしてみました。

でも、こうしても-tの値を減少させていくと、二重にechoってるようになるのが
どうしても解せません。なんでだよ!さすがにおかしいだろ!
やっぱり順次処理されてないのでは?

>>577
そんな格好いいのが出来るなら、敗北は認めなければなりませんね。
そこに美しさがあれば世界金メダルは譲ります。
0579名無しさん@お腹いっぱい。2012/08/09(木) 19:02:59.50
readでタイムアウトしてからechoまで0秒じゃないんだから、
そこでEnter打ったらなるんだよ
echoの前に sleep 入れてみたら確認できるだろ
05805562012/08/09(木) 19:06:32.81
>>579
あ、前のechoが残ってるのか、
どうやらオバカさん世界一の金メダルは私のもののようですね。ふっふっふっ。

本当にどうもありがとうございました。
0581名無しさん@お腹いっぱい。2012/08/09(木) 19:18:48.76
てゆーか、この程度なら、別に zsh の read -t とか、
BSD&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.74
sleep 1 だと遅延が蓄積して、どこかで2秒進んだりするから、
1秒未満でもうちょっと細かく再表示したいっていう意図じゃないの?
0583名無しさん@お腹いっぱい。2012/08/09(木) 19:26:03.35
>>581
せっかくそこまでするなら $( ) は ` ` にすべき。
0584名無しさん@お腹いっぱい。2012/08/09(木) 19:35:13.63
> sleep 1 だと遅延が蓄積して、どこかで2秒進んだりするから、
> 1秒未満でもうちょっと細かく再表示したいっていう意図じゃないの?

対話的シェルにリアルタイム保証なんてないから、read -t の時刻指定を
いくら細かくしたところで、マシン負荷が高くなれば、2秒どころかもっと
進む可能性はあるよ。そういう、対話的シェルで実現困難な仕様は、そもそも
盛り込むべきじゃないだろう。

ちょっとの負荷で2秒とびが嫌だっていうなら、拡張sleepに依存して
sleep 1 を sleep 0.9 ぐらいにするって手は、まあないわけではない。
read -t や sleep で指定する秒数をあまり小さくすると、無駄なマシン負荷が
増えるので、あまり小さくするのは推奨せんが。

>>583
Solaris の古いシェルとかで動かすことも考慮するなら、その通りだな。
まあ、そこは常識で分かると判断した。
0585名無しさん@お腹いっぱい。2012/08/09(木) 19:36:24.68
それをいっちゃあ、リアルタイムOSじゃないのに、xclockとかありえんって話になる
0586名無しさん@お腹いっぱい。2012/08/09(木) 19:39:33.95
date +%N で現在時刻のナノ秒を取得して、
それを sleep 0.123 とかの小数点以下に(計算の上)反映すれば
無駄にプロセスを使わずにうまく同期できるのでは?
0587名無しさん@お腹いっぱい。2012/08/09(木) 19:41:11.55
逆逆。
リアルタイムOSじゃないので、xclockだって、更新間隔が1秒より大きくなる
こともある。それが仕様。
xclock にだって不可能なことを、シェルスクリプトに求めるなんて、そもそも
そういう要求自体がおかしいってこと。
0588名無しさん@お腹いっぱい。2012/08/09(木) 19:43:59.25
>>586
高負荷時のことを考慮に入れるのなら、そんなんじゃ全くもって無理。

鯆管って、ほんとリアルタイム処理を分かってないなーって言っちゃうよ。
ちゃんと考えてみなよ。

どうしても分かんなければ説明するので、その場合は降参と宣言することw
0589名無しさん@お腹いっぱい。2012/08/09(木) 19:46:52.91
よし降参だ説明くれ
0590名無しさん@お腹いっぱい。2012/08/09(木) 19:47:45.98
>>588
高負荷時のことはどうでも良くて、
位相的にきっちり合わせたいということでしょ。

非同期で突然 sleep 1 を whileループで回せば、
最初から誤差が最大 0.99999... 秒になる。
これを、毎回 date +%N で 1秒未満の残り時間を把握しつつ
sleep 0.9821 とかすれば「位相」が同期する。
05915562012/08/09(木) 19:50:02.71
>>581
つーか、これでいいっすね。&使ってバックグラウンドに回しても表示効くのね。
しかもそいつをreadでインプット待ちにしておいて、インプット来たら殺すとかすげー。
でもこいつでsleep間隔いくら小さくしても、おいらの作ったスクリプトみたいに、echoの二重表示にならないのはどうしてなのか理屈がわからない。どうしてでしょう。
バックグラウンドジョブにしてるから?わかる人本当にお願いします。

>>582
そういう意図はありまくりんぐでしたけど、>>581さんのやり方でsleepの時間をさらに小さくするだけでいいように思います。負荷との兼ね合いですが。
0592名無しさん@お腹いっぱい。2012/08/09(木) 19:53:13.20
>>589
答えは、
 高負荷時には、date +%N の実行だけで数秒ないしそれ以上の
 時間がかかることがあるから
だ。

分かりやすい例でいうと、メモリが溢れていて、date コマンド
どころか、シェルまで swap に追い出されていて、スラッシング
しまくりの状況を考えてみるといい。

たとえメモリが足りててても、CPUその他のリソースが足りてなければ
数秒程度の遅延は普通に起こる。

まあ、鯆管的には、そんなに高負荷になる前にリソースなりマシンなりを
増やせってことになるので気にしてないだろうが、高負荷を気にしないなら
sleep 0.9 でも十分だ。

>>590
なるほど。
そういう意図であれば、確かに拡張sleepに依存するのもいいな。
0593名無しさん@お腹いっぱい。2012/08/09(木) 19:59:25.40
>>591
> でもこいつでsleep間隔いくら小さくしても、おいらの作ったスクリプトみたいに、echoの二重表示にならないのはどうしてなのか理屈がわからない。どうしてでしょう。

read と kill の間に、時間のかかるdateみたいな処理がないから、
その間にechoが動いてしまう可能性が確率的に非常に少ない。
そこにダミーのsleepでも入れれば二重表示にできるよ。
0594名無しさん@お腹いっぱい。2012/08/09(木) 20:01:56.63
>>593 の言う通りだ。

read x
sleep 1
kill $pid

に変更すれば、二重表示が簡単に確認できる。
05955562012/08/09(木) 20:12:11.80
>>593>>594
おぉ、本当だ。お前らかっこいいなぁ。ワクワクさん並に輝いてるわ。

どうも本当にありがとうございました。
05965272012/08/09(木) 21:43:53.53
後始末について聞いてみたかったんだけど
やめといたほうがいいのかな… (; ・ω・)
0597名無しさん@お腹いっぱい。2012/08/09(木) 21:56:40.30
終了したからいいよね。named pipeだった時の
>>541の後始末のタイミングは?
0598名無しさん@お腹いっぱい。2012/08/09(木) 22:20:41.64
よく知らんけど、たぶん、named pipe を使ったプロセス置換の実装の場合、
>>541 は、うまく動かない可能性もあるんじゃないかな。
まだ使用する前なのに消されてしまうことがあると予想。

ただ、コマンド hoge が既に named pipe をオープンし終えていれば、
ディレクトリツリーから named pipe が消されても、named pipe の実体は
残っている。その場合は動く。
というわけで、これは 消される前にオープンできるか否かという
race condition があるケースであり、うまいこと動くこともあるとは思う。

named pipe ではなく、pipe と /dev/fd/ を使った実装なら、
そういう race condition なしで動くだろうけど。
0599名無しさん@お腹いっぱい。2012/08/09(木) 22:32:03.31
>>598
<(...) や >(...) が named pipeで実装されてるFreeBSDのbashでちょっと
試してみたが、daemonみたいに子が先にexitして孫が残るケースでも無問題。

どうやら、named pipeに対する読み手と書き手が揃ってパイプがつながった段階で
unlink(2)される模様。プロセス実行中に先にunlinkされてる。
0600名無しさん@お腹いっぱい。2012/08/09(木) 22:34:14.50
検証どうも。
以外な結果だなあ。
孫が、引数をオープンする前に、たとえば10秒くらい待つような場合、
named pipe を管理するシェルはずっと待機しているってこと?
0601名無しさん@お腹いっぱい。2012/08/09(木) 22:35:20.24
おまえらのために実験してやったぞ
シェルの実装依存だ

zsh: 親が死んだらさっさと消す
bash: みんな死んでもbash自体が終了しても消さない
他は誰か試せ

テストコード
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
void check(char *path) {
if (access(path, F_OK) == 0) printf("%s exists\n", path);
else printf("%s does not exist\n", path);
}

int main(int argc, char *argv[]) {
sleep(1); check(argv[1]);
sleep(1);
if (fork()) {
printf("forked\n");
sleep(1); check(argv[1]);
sleep(1); printf("parent exits\n");
exit(0);
} else {
sleep(3); check(argv[1]);
sleep(1); printf("child exits\n");
exit(0);
}
}
0602名無しさん@お腹いっぱい。2012/08/09(木) 22:39:20.34
>>600
読み手と書き手が揃わない場合は、named pipe は放置されるww

例えば、
bash$ ls <(:)
bash$ exit

なんてやると、lsコマンドも :コマンドもnamed pipeにアクセスしないから、
/tmp/np-sh-XXXXX みたいなファイルが残ったまま bashが終了できてしまう。
bash終了時にはunlinkしないみたい。
0603名無しさん@お腹いっぱい。2012/08/09(木) 22:42:25.58
cat <(ls)
でも残るんだが
■ このスレッドは過去ログ倉庫に格納されています