1 名前:デフォルトの名無しさん mailto:sage [2018/09/22(土) 11:53:21.38 ID:BBiLRgnj0.net] !extend:on:vvvvv:1000:512 !extend:on:vvvvv:1000:512 シェルスクリプトに関する総合スレッドです。 スレ立て時は以下の文を先頭行に加えて下さい。 後のつけ忘れ防止の為に複数行重ねて追加推奨 !extend:on:vvvvv:1000:512 全般 ・荒しは無視しましょう。 ・丁寧な姿勢を心掛けましょう。 ・ネチケット(死語)を意識しましょう。 前スレ シェルスクリプト総合 その28 mevius.5ch.net/test/read.cgi/tech/1532397676/ VIPQ2_EXTDAT: default:vvvvv:1000:512:----: EXT was configured
491 名前:デフォルトの名無しさん mailto:sage [2018/11/06(火) 18:09:54.51 ID:dlj8br7m0.net] --helpオプションで出力される手引きの装飾についてだが less(1)ユーティリティは太字とにしてるね。
492 名前:デフォルトの名無しさん mailto:sage [2018/11/06(火) 23:18:09.57 ID:9jHKU1L00.net] シェルスクリプトは20年動くとか言ってるやつがいるけど、 あれ嘘だなぁ。 各シェルの実装は互換性がない部分があるし、 同じシェルでもバージョンが変わると微妙に動きが変わる POSIXという仕様があってもそれを完全に実装しているとは 限らないしバグもある。 20年前のJavaScriptと同じようなレベルだ。 そのJavaScriptも20年前のものが今でも動いているからねw 今のJavaScriptは本当にどれもで同じように動くようになったけど20年前は大変だった。 どのシェルでも同じように動くシェルスクリプトを書くのは今でも大変だよ 一度互換性テストでもやって準拠度100%を達成を競わせたほうが良いだろう
493 名前:デフォルトの名無しさん mailto:sage [2018/11/07(水) 03:53:59.64 ID:XzpCa+6s0.net] 「POSIXという一つの規格」がなぜそんなに強力だと思うのか分からない。 Pythonの公式文書やECMAが規格するJavaScriptと同等の立場でしょう。 もちろん,俺がシェルスクリプトを書くときは,俺がPythonやJavaScriptを書くときと同じく POSIXという共通規格に従うようにしているが,それは今後20年動かす為じゃない。
494 名前:デフォルトの名無しさん mailto:sage [2018/11/07(水) 09:26:49.70 ID:66xysPr5r.net] cronから実行しているシェル(スクリプト)があるんだけど 2重実行されると問題があるので そのシェルをくるむ親シェルを作って そこで事前にpkillで実行されているシェルおよびコマンドを無条件にkillしてる でも最近もともと実行してるシェルを複数回ループで実行したい要件が出てきた 単純に親シェルでループさせることを考えたけど pkillしてもループで再実行されてkill出来ずに2重実行される問題が出てくる シェルを親子孫の3階層にして新しく間に挟む子シェルでループさせ 親シェルのpkillではこの子と孫とコマンドをkillするといいと思うんだけど 階層が深くなって嫌だなと思うんだけど何かいい案ない? ちなみに孫シェルでループってのも考えたけど cron以外ではループさせたくない場合が多いので そこには手を加えずシンプルなままとしたいため考慮から外しました
495 名前:デフォルトの名無しさん mailto:sage [2018/11/07(水) 09:42:23.92 ID:+ld6QnEyM.net] pkillとか野蛮な方法じゃなくて、ちゃんとロックして、ロック取れなければ死ねばいいのでは?
496 名前:デフォルトの名無しさん [2018/11/07(水) 09:48:09.44 ID:bimd4khFa.net] もしflockコマンドがあればそれで可能な筈。
497 名前:デフォルトの名無しさん mailto:sage [2018/11/07(水) 09:48:23.84 ID:v2POOMdv0.net] どこまでの子プロセスとか残る可能性がとか条件が全然わからんが、シェルスクリプトを2重実行しないようにだけなら、その冒頭で、 [ -f /var/run/hogehogeshellscript.pid ] && kill -0 $(cat /var/run/hogehogeshellscript.pid) && exit 0 printf "%d" $$ > /var/run/hogehogeshellscript.pid 後始末で rm -f /var/run/hogehogeshellscript.pid が常套手段だな、俺は。「事前にpkillで実行されているシェルおよびコマンドを無条件にkillしてる」なんて、バグって残る場合しか考えられない(そんな動いているの殺していいの??)
498 名前:デフォルトの名無しさん mailto:sage [2018/11/07(水) 09:55:36.16 ID:zUpUn5UV0.net] そもそも考え方自体が理解しがたい こんなクソなことやり出すやつとは仕事したくない
499 名前:デフォルトの名無しさん mailto:sage [2018/11/07(水) 09:56:12.27 ID:+ld6QnEyM.net] >>497 cronで「しか」起動しないなら実用上問題ないかもしれんが、 まともなロックじゃないので2重起動されうる。
500 名前:デフォルトの名無しさん mailto:sage [2018/11/07(水) 10:01:20.98 ID:v2POOMdv0.net] >>499 まさか、タイミング的な話? >>494 で十分なもんだし、そんなシェスクリプト書きませんよ。そんな超短時間で多重起動されうるもんなんて、シェルスクリプトなんて書かない
501 名前:デフォルトの名無しさん mailto:sage [2018/11/07(水) 11:16:33.73 ID:UCphLCxy0.net] バグの言い訳をシェルスクリプトのせいにするなよ シェルスクリプト以外でもやり方は一緒だろ それともシェルスクリプトでは不可能で 他の言語なら可能な方法があるとでも言うのか? > そんな超短時間で多重起動されうるもんなんて、シェルスクリプトなんて書かない シェルスクリプト以外でいいんで、どうやるのか答えてみて
502 名前:デフォルトの名無しさん mailto:sage [2018/11/07(水) 11:40:25.66 ID:v2POOMdv0.net] バグの言い訳?? そんなタイミングにシビアなのは普通にCなりで書くけど?なんか知らんがシェルスクリプトで処理スピードに必死なヤツもいるけど、そんなに時間にシビアなら普通にCでするだろう(一部でも) てか、デーモンだろな。別にシェルスクリプトでデーモン書いてもいいけど、小回りが利くのはやっぱCなりの方だな
503 名前:デフォルトの名無しさん mailto:sage [2018/11/07(水) 11:41:10.13 ID:UCphLCxy0.net] いや、だから、C言語でいいんで、多重起動しない方法書いてみてって、 どうせそれがシェルスクリプトでも使えるだろ
504 名前:デフォルトの名無しさん mailto:sage [2018/11/07(水) 11:48:02.80 ID:v2POOMdv0.net] 何に絡んでいるのかわからん 粒度が全然違うことなぞCで何か書いたことがあるのならわかるだろう。>>499 がその粒度の話だからな
505 名前:デフォルトの名無しさん mailto:sage [2018/11/07(水) 11:50:35.19 ID:UCphLCxy0.net] 絡んでいない。C言語で多重起動しない方法は シェルスクリプトでも使えると言ってる だからシェルスクリプトで書かない理由にはならない
506 名前:デフォルトの名無しさん mailto:sage [2018/11/07(水) 11:52:41.86 ID:v2POOMdv0.net] だから、粒度って言ってるじゃん。わからんのだな。話にならんな
507 名前:デフォルトの名無しさん mailto:sage [2018/11/07(水) 11:55:02.47 ID:oFuFuwyAa.net] 結論の出ない子供同士の戦い ファイッ
508 名前:デフォルトの名無しさん mailto:sage [2018/11/07(水) 11:55:08.02 ID:UCphLCxy0.net] > 粒度って言ってるじゃん なんの説明にも反論にもなってない 粒度が違っても関係ない話だろ(他の人には「粒度」といい方で伝わってるはずw)
509 名前:デフォルトの名無しさん mailto:sage [2018/11/07(水) 11:56:38.86 ID:v2POOMdv0.net] うるせっw どうもシェルスクリプト大好き(後は私怨かなあとw)な絡みで、それ視点でしかなのでうやむやにしてんだけどね。言ったってたぶん聞かない人だから
510 名前:デフォルトの名無しさん mailto:sage [2018/11/07(水) 11:59:05.62 ID:v2POOMdv0.net] >>506 タイミング的な話なら、余計なことがない方が粒度が細かい=そっちにに決まっているだろう だがしかし、いくら粒度が細かくたってだから、デーモンでだろなだけどな
511 名前:デフォルトの名無しさん mailto:sage [2018/11/07(水) 12:06:12.02 ID:UCphLCxy0.net] > 余計なことがない方が粒度が細かい 粒度の使い方を待ちってるだけじゃないか で、デーモンにしないと多重起動は防げないって話をしてんのか? デーモンにすれば多重起動を防げる理由は? ほらな、突っ込まれるとこの程度、答えられないんだよw
512 名前:デフォルトの名無しさん mailto:sage [2018/11/07(水) 12:07:51.60 ID:8DqZdVO16.net] すまん 口を挟むけど 「 1. シェルスクリプトは各コマンドの起動時間やカーネルがファイルをどのように扱うということを 可搬な方法ではほとんど制御できない。 一方でCはそもそもOSがそれで書かれているように、上記の事柄を比較的簡単に実現できる。 2. ロックファイルを用いた多重起動防止アルゴリズムにはコマンドの制御時間やファイルの扱いを考える必要がある。 3. よってCと同じアルゴリズムをシェルスクリプトで記述しても それは運用に耐えるものでなくなってしまう。 だから無意味 」 ↑こういう理解でいいか?
513 名前:デフォルトの名無しさん mailto:sage [2018/11/07(水) 12:09:17.82 ID:v2POOMdv0.net] >>511 >粒度の使い方を待ちってる(間違ってる)だけじゃないか はあ? >デーモンにすれば多重起動を防げる理由は はあ?デーモンは一つ動けば十分だからな。ま・さ・か、デーモンにしても多重起動を防げないとか言い出してるわけ?だとしたらアホだな
514 名前:デフォルトの名無しさん mailto:sage [2018/11/07(水) 12:16:34.30 ID:v2POOMdv0.net] >>512 別に無意味とは言わないよ。俺は書かないというだけで。なんでシェルスクリプトでタイミング的な諸々をシェルスクリプトというある意味隠蔽された条件制約で悩まなくちゃならんねんってとこから。それならCでのほうがスッキリ小回りが利くしという 後は、超短時間で多重起動されうるもんなんてよりCで書くなという、そんな起動頻度のあるのは、スクリプトではしない
515 名前:デフォルトの名無しさん mailto:sage [2018/11/07(水) 12:21:30.58 ID:UCphLCxy0.net] >>512 > シェルスクリプトは各コマンドの起動時間やカーネルがファイルをどのように扱うということを > 可搬な方法ではほとんど制御できない。 それはプロセスの多重起動を防ぐ方法と関係ない > ロックファイルを用いた多重起動防止アルゴリズムにはコマンドの制御時間やファイルの扱いを考える必要がある。 コマンドの制御時間やファイルの扱いとかなんの話をしてるのか >>497 はアルゴリズムの間違いなのでロックファイルがどうとか関係ない (どうせC言語で作っても同じ間違いをするだろう) > よってCと同じアルゴリズムをシェルスクリプトで記述しても それは運用に耐えるものでなくなってしまう。 今はプロセスの多重起動の話でしか無いので、多重起動が出来ないならば運用に耐えられる それがシェルスクリプトできないわけがない。
516 名前:デフォルトの名無しさん mailto:sage [2018/11/07(水) 12:24:39.53 ID:UCphLCxy0.net] >>513 > はあ?デーモンは一つ動けば十分だからな。ま・さ・か、デーモンにしても多重起動を防げないとか言い出してるわけ?だとしたらアホだな デーモンが一つ動けば十分だとかそういう話をしてるんじゃない。 プロセスの多重起動を防ぐにはどうするかの話で、、 それはデーモンにしないと出来ないことではないだろ >>514 > なんでシェルスクリプトでタイミング的な諸々をシェルスクリプトというある意味隠蔽された条件制約で悩まなくちゃならんねんってとこから。 だから、なんでシェルスクリプトにこだわってるのか? こっちはお前が、プロセスの多重起動を防ぐ正しい方法を知らないんだろうなって思ってるんだよ。 だからC言語でいいから書いてみろと。 同じアルゴリズムはシェルスクリプトでも使えるから、シェルスクリプトかどうかの話じゃないって言ってんの で、C言語でプロセスの多重起動を防ぐ正しい方法を書けないんだろう? 出てないってことそういうことだ。シェルスクリプトだからと嘘をつくな
517 名前:デフォルトの名無しさん mailto:sage [2018/11/07(水) 12:24:57.98 ID:v2POOMdv0.net] >>513 >>497 はアルゴリズムの間違いなのでロックファイルがどうとか関係ない ただのイチャモンか。またか?コマンドのようにw
518 名前:デフォルトの名無しさん mailto:sage [2018/11/07(水) 12:26:20.56 ID:v2POOMdv0.net] >>516 ただのイチャモンやん。また、無茶苦茶やな。なにを問題にしているのかイミフ。いちゃもんのためのいちゃもんやなあ
519 名前:デフォルトの名無しさん mailto:sage [2018/11/07(水) 12:29:45.81 ID:UCphLCxy0.net] >>518 何を問題にしているかもわかってないのか? >>517 も指摘しているが、>>497 は多重起動チェックのアルゴリズムに問題がある シェルスクリプトだからこれしか出来ないという話ではない
520 名前:デフォルトの名無しさん mailto:sage [2018/11/07(水) 12:31:32.56 ID:UCphLCxy0.net] あ、>>517 って俺の書き込みか わかるように書けよw
521 名前:デフォルトの名無しさん mailto:sage [2018/11/07(水) 12:33:40.01 ID:v2POOMdv0.net] >>519 うーむ、だから粒度の問題と言っているんだけど。なにがアルゴリズムに問題があるの?cronで起動する大きな粒度では問題ないと思うけど あるとしたら、起動終了間近とか??それは別の話だろうしな???
522 名前:デフォルトの名無しさん mailto:sage [2018/11/07(水) 12:35:54.84 ID:v2POOMdv0.net] >>520 ああ、すまん。>>516 はあんたか。なんで絡んでるねんっ、何を問題にしてるねん??
523 名前:デフォルトの名無しさん mailto:sage [2018/11/07(水) 12:39:53.83 ID:v2POOMdv0.net] >>522 ああ、いいのかww 何を絡んでるのかイミフすぎ。場合によってって考えられないのかな? そもそも>>499 で十分で(十分だろう)というのに対して、その条件以外のツッコミに対して、その漠然として条件なら突き詰めると&俺にとって普通にシェルスクリプトで書かないってことなんだけどなあ 何が気に食わない、何が間違いなのかさっぱりだな
524 名前:デフォルトの名無しさん mailto:sage [2018/11/07(水) 12:40:36.54 ID:8DqZdVO16.net] >>515 俺は「プロセスの多重起動を防ぐ」というのを 「プロセスを一つ立ち上がっていることを感知する」 という仕組みを作ることだと思っていて、その方法の一つに 「プロセスが起動するときに特定のファイルを生成し そして終了するときそのファイルを削除する (そして そのファイルの有無によって多重起動を判断する)」 というものがある という認識。 「特定のファイル」はロックファイルと呼ばれる。 で ロックファイルアルゴリズムの問題点は非常に素早く二つのプロセスを立ち上げた時に 最初に起動したプロセスがロックファイルを生成し終える前に 二番目のプロセスがロックファイルが存在しないのを理由に立ち上がってしまう (結果として二重起動する) ということだと思っている。 このときに関わってくるのはファイルIOとかその辺のカーネル領域に片足突っ込んだ話なので Cではできるがシェルスクリプトでは難しいということだと考えたんだけど 違いますかね。
525 名前:デフォルトの名無しさん [2018/11/07(水) 12:43:18.47 ID:bimd4khFa.net] flockコマンド使えって。シェル単体ではそこまでやってくれるやつは多分ないだろうし。
526 名前:デフォルトの名無しさん mailto:sage [2018/11/07(水) 12:47:11.27 ID:v2POOMdv0.net] >>524 ロックファイル以外でも所詮OSで何らかの起動時のサポートが無ければCでも防げないと思うんだけど、どうだろう? なので、デーモンとして一つ起動して、それを活性化するのがなんだけどな
527 名前:デフォルトの名無しさん mailto:sage [2018/11/07(水) 12:56:45.06 ID:sVRrLKNr0.net] >>515 >>>497 はアルゴリズムの間違いなのでロックファイルがどうとか関係ない どこが間違ってるの? 最初にロック取って最後に解放する、これを間違ってると言うなら 正解を教えてよ。多分逃げるんだろうけど。
528 名前:デフォルトの名無しさん mailto:sage [2018/11/07(水) 12:58:34.71 ID:sVRrLKNr0.net] >>525 POSIXにないんでしょ、多分
529 名前:デフォルトの名無しさん mailto:sage [2018/11/07(水) 13:04:03.69 ID:jS/U4UFDM.net] flockがあればそれでいいけど、なくてもmkdirとかln -sで正しいロックが書けるよ
530 名前:デフォルトの名無しさん [2018/11/07(水) 13:04:59.10 ID:bimd4khFa.net] ロックファイルの有無だけでやる場合は open() で O_EXCL 指定してファイル作ろうとしないと駄目で、シェルスクリプトからこれがやれるかどうかはシェル次第になる。 そういう外部コマンド作って呼び出せば確実だが、それがありなら fcntl() や flock() 等を使ったもう少し信頼性の高そうなロックをした方が良いように思う。 ロックファイルだけでロックする場合はもう一つ強制終了させられた時にファイルが消せずに残る問題がある。 これはファイルのタイムスタンプを見て古ければ動いていないとみなす方法である程度回避可能だが、その場合は動いているプロセスが定期的にファイルを touch する等して更新する必要がある。 しかしそれでも SIGSTOP により停止していただけだったら役に立たない。
531 名前:デフォルトの名無しさん mailto:sage [2018/11/07(水) 13:05:12.80 ID:8DqZdVO16.net] https://qiita.com/richmikan@github/items/6ca1ec3b354ae2f5505d 「シェルスクリプト 排他制御」でググったらこんな記事があったよ。
532 名前:デフォルトの名無しさん [2018/11/07(水) 13:06:37.34 ID:bimd4khFa.net] >>529 ああ。それでもできるか。
533 名前:デフォルトの名無しさん mailto:sage [2018/11/07(水) 13:22:04.61 ID:v2POOMdv0.net] なるほど、OS内でキッチリ一元管理しているナニカに頼ればいいのか&あるのか
534 名前:デフォルトの名無しさん mailto:sage [2018/11/07(水) 13:40:10.94 ID:UCphLCxy0.net] >>524 > で ロックファイルアルゴリズムの問題点は非常に素早く二つのプロセスを立ち上げた時に > 最初に起動したプロセスがロックファイルを生成し終える前に > 二番目のプロセスがロックファイルが存在しないのを理由に立ち上がってしまう > (結果として二重起動する) 正しくない 正しいロックファイルアルゴリズムであれば、素早く二つのプロセスを立ち上げても問題ない あんたが書いたそれはは典型的な間違ったロックファイルアルゴリズム(そして>>497 も同様) アルゴリズム自体の問題なのでシェルスクリプトかどうかは関係ない 直接的な解答ではなくて関連した話題になるが、多重起動防止以外でも重要だから読んどけ https://www.ibm.com/developerworks/jp/linux/library/l-sprace/index.html > 単純な解決方法は、open()をフラグO_WRONLY | O_CREAT | O_EXCLで使うことです https://www.ipa.go.jp/security/fy20/reports/tech1-tg/2_05.html > これを避けるためには先に述べたとおり、テンポラリファイルを生成するときに O_EXCL を指定すればよい。
535 名前:デフォルトの名無しさん mailto:sage [2018/11/07(水) 13:43:12.68 ID:UCphLCxy0.net] もう少し引用する範囲を広げる > これを避けるためには先に述べたとおり、テンポラリファイルを生成するときに O_EXCL を指定すればよい。 > これを POSIX シェルで行うには、set -C を使う。set -C は noclobber オプションを有効にする。 > noclobber が有効な場合、> によるリダイレクトでの open には O_EXCL が指定される。 > これを使ってテンポラリファイルの生成に挑戦し、失敗したときは終了するには以下のようにする。 > また、ここでは TMPDIR が指定された場合には使うようにしている。
536 名前:デフォルトの名無しさん mailto:sage [2018/11/07(水) 13:44:46.92 ID:UCphLCxy0.net] こっちはおまけ、どうせググるんだろう?w pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#set
537 名前:デフォルトの名無しさん mailto:sage [2018/11/07(水) 13:45:31.17 ID:v2POOMdv0.net] ほんと場合によってってって無いやつだな。原理主義者か?
538 名前:デフォルトの名無しさん mailto:sage [2018/11/07(水) 13:49:03.61 ID:8DqZdVO16.net] >>534 そうなんだ。知らなかった。 教えてくれてありがとうございます。
539 名前:デフォルトの名無しさん mailto:sage [2018/11/07(水) 13:57:13.33 ID:UCphLCxy0.net] ロックの確認とロックかけるのをアトミックにやらないとか まともにロック処理やったことがない証拠だよ これは初心者は誰でもやる典型的な間違いだからな 基本を知らずに独自の思いつきで実装するからそうなる 言われれ初めて気づく。だが一回言われればこうやれば 解決できるのかと深く記憶する話だから、単純に知識が欠けてるということ だから他の言語でもどうせ同じなんだろということ。
540 名前:デフォルトの名無しさん mailto:sage [2018/11/07(水) 15:22:16.58 ID:8DqZdVO16.net] ksh --helpは出力される手引きが装飾されてるね
541 名前:デフォルトの名無しさん mailto:sage [2018/11/07(水) 15:56:27.81 ID:A+xcJusCM.net] 最初っから主張の根拠を提示すれば良かったのに 何だかんだで下らないレスが続くの止めて欲しい
542 名前:デフォルトの名無しさん mailto:sage [2018/11/07(水) 17:41:34.46 ID:P+AQGnBFa.net] echo "echo \"Hello, world\!\"" これ実行したら echo "Hello, world!" にならない echo "Hello, world\!" なぜか!だけ手前についてしまう
543 名前:デフォルトの名無しさん mailto:sage [2018/11/07(水) 18:45:58.27 ID:XzpCa+6s0.net] >>542 それスクリプトにしてやってみ。 多分期待どおりの出力になる。
544 名前:デフォルトの名無しさん mailto:sage [2018/11/07(水) 18:49:27.43 ID:XzpCa+6s0.net] 間違えてた。 「echo "echo \"Hello, world!\""」にして。 スクリプトの中ではPOSIX互換のインタラクティブシェルは 履歴展開をしないので上手くいく。
545 名前:デフォルトの名無しさん mailto:sage [2018/11/07(水) 19:24:02.67 ID:UCphLCxy0.net] そういやkshで思い出したけど、 ksh88ってもしかして比較的最近(今も?)使われてたりする? ksh88っていうぐらいだから1988年だろ?ksh93っていうぐらいだから1993年だろ? 流石にksh88はなんて30年前の化石使われてないだろ?と思ったけど Solaris 11 でこんなこと書かれてたんだよね。意外と最近まで使われていたのかなぁ?と https://docs.oracle.com/cd/E26924_01/html/E25934/userenv-1.html > シェルの変更 - デフォルトのシェル /bin/sh が ksh93 にリンクされるようになりました。 > レガシー Bourne シェルは /usr/sunos/bin/sh として使用可能です。 > 旧バージョンの ksh88 は、shell/ksh88 パッケージの /usr/sunos/bin/ksh として使用可能になっています。 Solaris 11が最新版って言っても2011年11月9日リリースなので2日後に7年前のOSになるけど (でもサポートはSolaris 10が2021年までなのか・・・) そしてksh93の機能でこんな事書いてたんで、$(( )) が使えないシェルはksh88だったんだなって思ったところ https://www.ibm.com/support/knowledgecenter/ja/ssw_aix_72/com.ibm.aix.osdevice/korn_shell_enhanced.htm
546 名前:デフォルトの名無しさん mailto:sage [2018/11/07(水) 20:49:34.06 ID:nHlOtVrla.net] >>544 できたd (でも都合上コンソール開いてコピペで使いたかったんや)
547 名前:デフォルトの名無しさん mailto:sage [2018/11/07(水) 20:55:26.75 ID:XzpCa+6s0.net] >>545 Solaris 10のがPOSIXに準拠してることになってるせいで "$@"じゃなくて${1+"$@"}と書かないといけなかったりして面倒だよねw
548 名前:デフォルトの名無しさん mailto:sage [2018/11/07(水) 21:01:40.12 ID:XzpCa+6s0.net] >>546 「echo "echo \"Hello, world"'!'"\""」とかどうだろう。 参考: https://www.gnu.org/software/bash/manual/html_node/History-Interaction.html#History-Interaction History expansions are introduced by the appearance of the history expansion character, which is ‘!’ by default. Only ‘\’ and ‘'’ may be used to escape the history expansion character, but the history expansion character is also treated as quoted if it immediately precedes the closing double quote in a double-quoted string.
549 名前:デフォルトの名無しさん mailto:sage [2018/11/07(水) 21:21:50.95 ID:UCphLCxy0.net] >>547 ksh・・・お前が諸悪の根源だったか https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=861743 > % posh -u -c 'echo "$@"' > posh: @: parameter not set poshはpdkshからフォークしている > posh (0.0.1) unstable; urgency=low > * Initial release. (copied from pdksh 5.2.14-6). closes: bug#150431. そしてシンプルな(笑)解決方法をありがとう (if書くのはもっと面倒だった) もっとバッドノウハウあったら教えてくれ!
550 名前:デフォルトの名無しさん mailto:sage [2018/11/07(水) 22:18:01.95 ID:XzpCa+6s0.net] >>549 あー。分かってると思うがこれは俺が考えた方法じゃない。 古いGNU grepでegrepコマンドを https://git.savannah.gnu.org/cgit/grep.git/tree/src/Makefile.am?h=v2.5.1#n23 ↑こうやって作ってたのを見掛けてさ。 これはすごい方法だと思って自分のシェルスクリプトに取り入れた。 でもPOSIX 2013でset -uが有効のときでも空の変数$@および変数$*がエラーにならない っていうことが決定されたのでもう不必要。 pubs.opengroup.org/onlinepubs/9699919799.2013edition/utilities/V3_chap02.html#tag_18_25_18
551 名前:デフォルトの名無しさん mailto:sage [2018/11/08(木) 00:40:04.66 ID:rJTiWJ810.net] >>550 modernishでも言及されてた。時代遅れのワークアラウンドだってw でも現存するシェルに蘇っておるのじゃよ 昔の人には有名な回避策なのかな? https://github.com/modernish/modernish/blob/master/README.md > BUG_PARONEARG: When IFS is empty on bash 3.x and 4.x (i.e. field splitting is off), > ${1+"$@"} is counted as a single argument instead of each positional parameter as > separate arguments. To avoid this bug, simply use "$@" instead. (${1+"$@"} > is an obsolete workaround for a fatal shell bug, FTL_UPP.)
552 名前:デフォルトの名無しさん mailto:sage [2018/11/08(木) 06:54:13.32 ID:RnVV1kHy0.net] modernishおもしろいね。 modernishプロジェクトはcase文の条件の先頭に開き丸括弧を付けてるのか。 pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_09_04_05 ここには確かに開き丸括弧を前置してもいいとあるけど一般的には省略されるでしょ。 なにかこれも旧時代のシェルの不具合への回避策なのかな。 それこそGNU Bash 3.xで動かない,とか。
553 名前:デフォルトの名無しさん mailto:sage [2018/11/08(木) 21:39:50.16 ID:rJTiWJ810.net] >>552 やっとmodernishに興味を持ってくれた人がw まあ俺もバグ情報とか参考になるなって程度にしか見てないんだけど > modernishプロジェクトはcase文の条件の先頭に開き丸括弧を付けてるのか。 それ見た時、何この文法?modernishでそこまで拡張できるの?って驚いたw 単なる普通の文法だったわけだけど > それこそGNU Bash 3.xで動かない,とか。 少なくともbash 2.03では開き括弧なくて動くよ
554 名前:デフォルトの名無しさん mailto:sage [2018/11/08(木) 21:43:11.48 ID:rJTiWJ810.net] 話変わるけど、 foo | bar みたいなコマンドで fooからたくさん出力されるけど、barの処理が遅いってとき fooからの出力ってブロックされるのかな? なんか20〜30行ぐらいでブロックされるような 出力の停止、遅延が起きてる気がする メモリにバッファリングするだろうから、それが溢れないような処置として そういう仕様は理解できるけど、どこかに書いてあるのかな? シェルの仕様っぽい気がするけど、OSも絡んでいそうな気もする
555 名前:デフォルトの名無しさん mailto:sage [2018/11/08(木) 21:57:11.56 ID:M53t5TPP0.net] >>554 タネンバウム先生の本は読んでるんだよね?
556 名前:デフォルトの名無しさん mailto:sage [2018/11/08(木) 21:59:18.34 ID:rJTiWJ810.net] >>555 読んでないよ。どれ読めばいい?
557 名前:デフォルトの名無しさん mailto:sage [2018/11/08(木) 22:12:14.64 ID:RnVV1kHy0.net] 全然かわいくないアライグマの表紙の本じゃない?
558 名前:デフォルトの名無しさん mailto:sage [2018/11/08(木) 22:21:06.03 ID:rJTiWJ810.net] お、再現した i=0 while :; do i=$((i+1)) echo test$i echo log$i>&2 done | while read line; do echo $line sleep 3 done パイプの前で無限ループで標準出力と標準エラー出力に高速に出力してるとき パイプの後ろの遅い標準入力から入力の処理によって パイプの前の標準エラー出力への出力がブロックされてる 7400行(64KB程度?)ぐらいまでは、パイプの後ろの処理を待つことなく高速に 標準エラー出力に出力するが、それ移行は1行ずつ出力するようになった。
559 名前:デフォルトの名無しさん mailto:sage [2018/11/08(木) 22:23:20.00 ID:rJTiWJ810.net] >>557 ¥ 15,449 円+350円 もするのかー 高いなー
560 名前:デフォルトの名無しさん [2018/11/09(金) 04:14:42.04 ID:hZOut+vv0.net] >>558 それ普通のマルチタスクOSでの動作なのでは? 昔々のMS-DOSとかのシングルタスクOSでは一回ファイルに書き出してから次のコマンドに読ませるので無限に出力するやつはだめだけどな。
561 名前:デフォルトの名無しさん mailto:sage [2018/11/09(金) 04:37:21.46 ID:WTWdJdbs0.net] パイプは、入力が来るまで、ブロックされる
562 名前:デフォルトの名無しさん mailto:sage [2018/11/09(金) 05:22:03.56 ID:3ZHBVzZ50.net] いわゆる普通のプログラミング言語(PythonやCやJavaScript)に対して,シェルスクリプトを作る上で気をつけてることってある? 例えば「局所変数や局所関数が宣言できないのでなるべく使わない」とかさ。
563 名前:デフォルトの名無しさん mailto:sage [2018/11/09(金) 08:16:02.70 ID:UVRb8J0Z0.net] >>560 並列で動作するのは当然だが、今話しをしてるのは、 一つのプロセスが、もう一つのプロセスの動作を止めるっていうところだよ >>561 逆ね。パイプは(パイプ先が)入力を受け取るまでブロックされる こっちはどばどばーっと出し続けようとしてるのに、相手が受け取ってくれないから 出せなくなるんだよ。って話
564 名前:デフォルトの名無しさん mailto:sage [2018/11/09(金) 08:22:51.21 ID:PBD+wepW0.net] パイプはカットすればいい
565 名前:デフォルトの名無しさん mailto:sage [2018/11/09(金) 08:36:27.28 ID:UVRb8J0Z0.net] >>562 個人的な特殊な状況下で気をつけてることならたくさんあるんだけどな パイプを(なるべく)使わないとかwww そうさなぁ、例えば意図せぬエラーで落ちるように、set -eを使う場合は 挙動をよく理解して使うこととかかな set -eは戻り値がエラーになった時点で中断される set -e foo() { echo foo begin; bar; echo foo end; } bar() { echo bar begin; baz; echo bar end; } baz() { echo baz; false; } foo これを実行すると、foo -> bar -> baz の呼び出しの流れが、bazのfalseで中断されて foo begin bar begin baz と表示されるんだが foo の代わりに if foo; then :; fi と実行すると なんと、foo end も bar end も表示されるんだよ つまり foo を if や && や || と組み合わせて使うと、エラー中断機能が無効化される だから、比較関数みたいに if foo; then という使い方を想定している関数は 中でしっかりエラーチェックをしておくこと 他の言語の例外みたいに考えてはいけない
566 名前:デフォルトの名無しさん mailto:sage [2018/11/09(金) 08:39:06.36 ID:UVRb8J0Z0.net] ↑ これが理由で、set -eは使うな派もいるらしいねw >>562 > 例えば「局所変数や局所関数が宣言できないのでなるべく使わない」とかさ。 俺は訳あってそうしてるけど、特定のシェルに限って良いのなら localもしくはtypesetで局所変数使えるよ ただし、他の言語と違ってレキシカルスコープじゃなくて ダイナミックスコープなので注意が必要 これも気をつけていることかな
567 名前:デフォルトの名無しさん mailto:sage [2018/11/09(金) 08:44:20.66 ID:UVRb8J0Z0.net] あと他の言語でも同じだけどshellcheckは基本やね ダブルクォートでくくるとか、shellcheckで警告出るものは ここでグダグダ書かないよ。
568 名前:デフォルトの名無しさん [2018/11/09(金) 09:08:37.30 ID:JsSTi+Gxa.net] >>563 パイプが詰まってんだから停止させるしか方法ないと思うが? バッファ大きくしても出力側が速いなら何れ突っ掛かる事になるよね。
569 名前:デフォルトの名無しさん mailto:sage [2018/11/09(金) 09:16:09.65 ID:UVRb8J0Z0.net] >>568 そりゃそうだよねって話ではあるんだけどさ、 パイプで何かに繋いだがために処理が遅くなることもあるよなって思ってね
570 名前:デフォルトの名無しさん mailto:sage [2018/11/09(金) 09:18:07.88 ID:FKBIIb3sa.net] 明らかにそんなレベルの回答求めてないよねっていう語りたがり
571 名前:デフォルトの名無しさん mailto:sage [2018/11/09(金) 09:24:33.15 ID:UVRb8J0Z0.net] ん? あぁ、質問はコレね > メモリにバッファリングするだろうから、それが溢れないような処置として > そういう仕様は理解できるけど、どこかに書いてあるのかな? > > シェルの仕様っぽい気がするけど、OSも絡んでいそうな気もする
572 名前:デフォルトの名無しさん [2018/11/09(金) 09:31:46.72 ID:JsSTi+Gxa.net] どう考えてもOSの仕様だろう。
573 名前:デフォルトの名無しさん mailto:sage [2018/11/09(金) 09:40:49.31 ID:3ZHBVzZ50.net] >>565 ありがとう。set -eは鬼門だね。前に棘かなにかでも纏められてた。 ところで パイプ使わないのはどうしてだ? シェルスクリプトは入出力指向なんだから積極的にパイプを活用すべきでは。
574 名前:デフォルトの名無しさん mailto:sage [2018/11/09(金) 09:55:47.54 ID:UVRb8J0Z0.net] >>573 パイプ使わないのはシェルスクリプト内部で完結する場合の話ね 外部コマンドとのインターフェースでは使う (内部で)使わない理由は変数の共有がやりづらいから ま、これは特殊な事例なのでw
575 名前:デフォルトの名無しさん mailto:sage [2018/11/09(金) 10:07:47.85 ID:3ZHBVzZ50.net] ああ。たしかにパイプ越しに変数を参照させようと思ったらexportして環境変数にしなくちゃらんもんな。
576 名前:デフォルトの名無しさん mailto:sage [2018/11/09(金) 10:31:29.63 ID:UVRb8J0Z0.net] > ああ。たしかにパイプ越しに変数を参照させようと思ったらexportして環境変数にしなくちゃらんもんな。 もうちょっと説明すると foo() { output | bar | baz } fooで見えてる変数を、bar, bazに見せるのは簡単なんだよ。 exportしなくても見せられる。 outputが出力する1行をbarが解析して変数に入れたとして、その変数を bazで見ることはできない(barでexportしても無理) bazが複数行の入力を集計した結果の変数をfooで見ることが出来ない。とかね 1データを1行に詰め込めればパイプ経由でのデータ受け渡しは可能だが それができないデータだと難しい 他の言語でやれって? それをシェルスクリプトでやらなきゃいけないというのが個人的な特殊な状況下というわけ
577 名前:デフォルトの名無しさん mailto:sage [2018/11/09(金) 17:10:16.74 ID:3ZHBVzZ50.net] シェルスクリプトでそのコマンドが実行された行数を取得する方法ってあるかな。 #!/usr/bin/env bashにすれば${LINENO}変数にその位置が格納されてるので簡単なんだけど やっぱりもうすこし汎用的な方法で実現したい。
578 名前:デフォルトの名無しさん mailto:sage [2018/11/09(金) 19:41:43.60 ID:UVRb8J0Z0.net] >>577 LINENOしかないよ。ただしご存知の通りLINENOは使えないシェルがある。 dashなんか機能的には搭載されてるがdebianなどでは無効にされてるというw 更にシェルによっては関数呼び出しを行った時にソースコードの行数ではなく 関数の頭からの行数になっていて、それも0から始まるものと1から始まるものがある まともに使えるのはbashだけかな
579 名前:デフォルトの名無しさん mailto:sage [2018/11/09(金) 20:27:42.80 ID:3ZHBVzZ50.net] >>578 だよね〜。ファイルの中での自分の位置を調べるのはシェルスクリプトでは無理っぽいね。 Cのassert()関数みたいなのを自作したかったんだけど 機能が落ちるのは嫌だな(もういいけど) ああ ちなみに > 関数呼び出しを行った時にソースコードの行数ではなく > 関数の頭からの行数になっていて これGNU Bashのことを言ってるのなら関数じゃなくて別名にすればO.K.だよ
580 名前:デフォルトの名無しさん mailto:sage [2018/11/09(金) 21:02:47.30 ID:UVRb8J0Z0.net] >>579 シェルスクリプトの世界にJavaScriptのトランスパイラ技術が導入されて ソースコードの一行一行にLINENOを設定するコードを埋め込めば 解決できると思うんだが、流石にそれをやろうとする人はいないかなw > これGNU Bashのことを言ってるのなら関数じゃなくて別名にすればO.K.だよ alias?うーん、なんか別の問題がでそう。 でもbashじゃなかったと思う。 前に調べたときのコードを見てみたが、 関数の頭からの行数になるのはzsh, dash, busybox ashで zshは0から始まる。他は1から始まる。bashとkshはソースコードの行数で取れる。 バージョンは詳しく調べてないから多分古いやつは使えなかったりすると思う なので他のシェルでエラーが起きたら、bashで実行してエラーの行番号を調べたりしているw
581 名前:デフォルトの名無しさん mailto:sage [2018/11/10(土) 09:07:56.28 ID:lBOHSSIo0.net] たとえばシェルアーカイブってPOSIXシェルでも可能だよね。 ああいう感じで自分が含まれるファイルを自分で走査できるんなら 行位置も取得できないかなぁと思ったんだよね……。 しつこいけどシェルスクリプト版のassert()関数が欲しい っていうか作りたいんだよねぇ
582 名前:デフォルトの名無しさん mailto:sage [2018/11/10(土) 09:34:29.76 ID:8OkJCHKT0.net] >>581 assertだけなら簡単かもしれないな。 assert関数の中で全てを処理するのは難しいと思う。自分のスクリプト名でさえ取得できない場合があるから 仮に取得できたとしても、何かしらのマーカーがないとどのassertかが区別できない。 (全ててのassertに区別できるマーカーを入れるっていうのなら可能だけどw) 前提としてLINENOが取得できないのはどうしようもないのでコード変換を行なう foo() { asesrt [ i -gt 0 ] } みたいなコードがあったら以下みたいに、行番号を埋め込むプログラムを作る (ファイル名もあったほうが良いかもしれない) foo() { asesrt 2 [ i -gt 0 ] } これはPOSIXシェルスクリプトの範囲でもできる。一行づつ読んでパターンにマッチしたら変換するだけ (複数行文字列やヒアドキュメントがあったら面倒だけど、対応してませんでもいいと思う) あとは以上の変換処理を行って実行するラッパースクリプトを作って実行する 変換したコードはevalもしくはシェルにパイプで流し込むことで実行できる。
583 名前:デフォルトの名無しさん mailto:sage [2018/11/10(土) 09:39:54.31 ID:8OkJCHKT0.net] あー、そうか、assertか、ならデバッグ時のみしか有効じゃなくていいな。 なら、普通にスクリプトを実行したときは、 何もしないassert関数になって、 debug.sh script.sh みたいにしたら、 コード変換を行ってから実行すれば良いのか 意外と自然な感じで作れそうw
584 名前:デフォルトの名無しさん mailto:sage [2018/11/10(土) 09:49:06.14 ID:8OkJCHKT0.net] assert失敗時に強制的に停止させるのはkill $$で行けるかな? サブシェル内でも一応停止できるようだけど
585 名前:デフォルトの名無しさん mailto:sage [2018/11/10(土) 16:43:37.38 ID:lBOHSSIo0.net] 色々考えてくれてマジでありがたい 確かにassert()関数はデバッグの時だけ有効になればいいから外部からスクリプトファイルを操作するという方法も なんら不自然ではないな。 C言語のようにNDEBUG変数の有無によって処理を分けようとしてたけど そっちのほうが柔軟な処理ができるのでいいね。 ていうかC言語と違ってシェルスクリプトのなかで安全・確実に変数を取り扱うのは厄介だから 寧ろNDEBUG変数は害悪ですらあるなw
586 名前:デフォルトの名無しさん mailto:sage [2018/11/10(土) 19:36:31.81 ID:8OkJCHKT0.net] >>585 何もしないassert関数と書いたが、コメントの形でassertを入れるのはどうだろう? これなら関数呼び出しすらないので、(わずかな)パフォーマンス低下も発生しないし 仮にスクリプト内でassert関数を使っていても問題ない assert有効時は、長い名前に変換すれば良い
587 名前:デフォルトの名無しさん mailto:sage [2018/11/10(土) 19:38:01.66 ID:8OkJCHKT0.net] あと、デバッグモード、assert関数有効時だけど、終了ステータスを変えてしまうことに注意な foo() { false # assert [ なんちゃら ] echo $? } という場合、本来はechoで1と表示されるけど、単純にこのように変換してしまうと、 assert有効時に$?がassertの結果になってしまう だから変換後はこんな感じかな? ||:を使うことでset -e状態でも落ちなくできる foo() { false assertooooo 3 [ なんちゃら ] ||: echo $? } assertooooo() { EXIT_STATUS_BACKUP=$? LINE_NUMBER=$1 shift if "$@"; then return $EXIT_STATUS_BACKUP else echo "エラー $LINE_NUMBER" >&2 exit 1 fi }
588 名前:デフォルトの名無しさん mailto:sage [2018/11/10(土) 19:42:53.17 ID:8OkJCHKT0.net] > 仮にスクリプト内でassert関数を使っていても問題ない ちょっとわかりづらかったな スクリプトでassertという名前の関数を別の用途で使っていた場合ってことね
589 名前:デフォルトの名無しさん mailto:sage [2018/11/10(土) 19:44:37.42 ID:8OkJCHKT0.net] うぬ、ここはkillにするんだった else echo "エラー $LINE_NUMBER" >&2 kill $$ fi
590 名前:デフォルトの名無しさん mailto:sage [2018/11/10(土) 19:49:50.91 ID:8OkJCHKT0.net] (ま、あとは . ドットコマンド で読み込んだ外部スクリプトはどうするか問題があるんだがなw)
591 名前:デフォルトの名無しさん mailto:sage [2018/11/10(土) 20:03:55.71 ID:8OkJCHKT0.net] あー、バカだ assertooooo 3 [ なんちゃら ] ||: じゃなくて assertooooo 3 [ なんちゃら ] &&: だった 上はset -eでも落ちなくし、かつ終了ステータスを問答無用で0にする方法(エラーの時 : を実行する) 下がset -eでも落ちなくし、かつ終了ステータスはそのまま保つ方法