シェルスクリプト総合 その29
■ このスレッドは過去ログ倉庫に格納されています
シェルスクリプトに関する総合スレッドです。 全般 ・荒しは無視しましょう。 ・丁寧な姿勢を心掛けましょう。 ・ネチケット(死語)を意識しましょう。 前スレ: シェルスクリプト総合 その28 http://mevius.5ch.net/test/read.cgi/tech/1532397676/ >>216 逃げるも何も「文句をつける対象を理解してない」のにどう相手をすれと?あんたにこれ以上こまごまこまごま教えてなきゃならんのか? だったら、逃げるよ POSIXはシェルスクリプトだけを〜とか、じゃあC言語のことなんですかねぇ でもC言語でも空のディレクトリで * が返ってくることはないし ほんと何が言いたいんだかw POSIXはシェルスクリプトだけを考えてるわけではないから → Ruby・・・空の配列を返す → Perl・・・空の配列を返す → PHP・・・空の配列を返す → C言語・・・空の配列を返す シェルスクリプト以外は空の配列を返します。 >>218 ,220 はあ...最後な >>194 ,195をよーく読め。なんでそれがbashでになってるのかも >>222 またそれか。よく読んでも、そうした理由は書いてない。 Supports rule 3 in the Shell and Utilities volume of IEEE Std 1003.1-2001, Section 2.13.3, Patterns Used for Filename Expansion. >>225 モロ体現してありがたい。オモロイなあんたは >>226 何度も言ってるが、 俺が聞いているのは、そういう仕様にした"理由"であって 仕様の場所は聞いてはいない。 ほんと、脊髄反射しかしねーなw >>228 言っているけど。「読めれば」そう書いてあるんだけどな。「読めない読めない」言われてもしょうがない あんただって、「空」だったらマズいときもあるって認めてるやん 本当にただただ「認めたくない」だけなんだな。その「コロ」っとあんたの原点に戻るあたり まあ、がんばりや そして面白いのが、シェルスクリプトは glob で見つからない場合に 検索パターンを返すのに対して、シェルスクリプト以外では 見つからない場合に、空のリストを返すって所だな。 >>229 お前、マズイときもあるし、マズくない時もあるって 自分で認めてるやんw ということはお前の主張は、所詮マズイときの例でしかなく マズくない時には当てはまらないってことになるんだぞ わかってるのか?お前の主張が崩れてるの で、シェルスクリプト以外は空のリストを返しているのに シェルスクリプトだけは、見つからなかった時に * という 文字列を返すという仕様にした理由は? 結局、一番マトモな理由は >>191 が書いた > おそらく, そういう仕様をきめてからそういう動作をさせたわけではないとおもいます. これだけなんだよな。特に理由はない。 (深く考えずに)そうしてしまった。 もちろん、正式なドキュメントとして この理由が、書かれている文書は見つかってないがね。 あ、みなさん。もし ID:b0dEtQwc を擁護したい人がいるならば ID:b0dEtQwc が示したドキュメントの中から、 「そういう仕様にした"理由"」を書いてある所を指摘して構わないんですよ? ないでしょう? 誰も指摘しないもんね。それが証拠だよ。 何言っているの? >この仕様、なにか便利なの? が、お前の原点だろ?それ以後「認めなたくない」のであーだこーだ言っているだけだな とうとう誰とも言えない人に頼るようになったか...ww >>234 ちゃんと流れを読むように 107 自分:デフォルトの名無しさん[sage] 投稿日:2019/04/04(木) 17:59:04.72 ID:opkeFDjY [4/21] >>104 聞いてるのは仕様ではなくて、 どうしてそうしたかの理由です。 >>236 流れというかレスを読めないあんたに言われたくないw いや、原点の話でしかないな。あんたの都合に(それもあんたの都合の良いようになだけな)合わせる必要性はこれっぽちもないな とりあえず、原点の問題は解消した&マズい場合もあるそれが理由ってことも解消したってことで、おしまい https://linuxjm.osdn.jp/html/LDP_man-pages/man7/glob.7.html > において、*.gif ファイルが全くない場合でも、 これは空のリストに展開されるため、エラーにならない。 > しかし POSIX では、文法的に正しくないパターンや、 マッチがなかったパターンは、 そのまま変更されずに残されることになっている。 > bash では、次のコマンドで昔からの振る舞いに設定することができる。 > > shopt -s nullglob なぜ昔からの振る舞いから替えたのか?その理由が謎 (理由を明確に述べているドキュメントがない) >>237 おしまいなんで、あんたは消えていいです。 1ヶ月後にちゃんと答えてください(笑) > POSIXはシェルスクリプトだけを考えてるわけではないから ↑これも結局何が言いたいのか不明だったな まあ、何も考えずに(調べずに)シェルスクリプト以外の言語でも * を返してるはずだって思い込んだんだろうなw (実際には見つからない場合は空のリストを返します。) なにか勝ち誇って妄想全開のようだが、全然違う >>195 をよく読もうな。>>226 と注目すべきとこあげたのに 他の言語でもglobなんて自ら実装したりはしないんじゃないの。単にそのオプションがデフォルトでは設定されていない、オプションが設定できるのは設定すれば同じになるんじゃないの。妄想お疲れさん > POSIXはシェルスクリプトだけを考えてるわけではないから ↑これで何が言いたいのかを書けば済む話 それが出来ないのはなぜだろうw あ、ちなみに「注目すべきとこ」には何も書いてませんよ。 いつもどおりです。 ほんとーーにっ、「読めない」のな、この脊髄反射マンっw 読めないって言わずに、具体的に引用すればいいだけなのに それをしないのは、結局引用する場所がないからなんだよね 「無い」から「引用できない」に変わったけど、同じパターンやな。そして前言はなかったことにという前々からの同じパターン >>246 はとりあえずレスしてみましたってだけで 中身がなにもないことに、皆さん気づきましたか? なんか少しは自分を見直すとかあって、ここでもこんなクソ(俺のも含めて)なレスの応酬もなく、見てためになる万人が楽しめるレス、Q&Aになるかと思ったが、無理かやっぱ(偉そう偉そう) そりゃ無理かっ。なんか急に飽きた、じゃな はい、コイツは何度目かの逃亡宣言です。 また懲りずに来ますよw bashの算術計算で小数を使う方法ってないです? +=で加算したいんですが >>250 それ俺も欲しいんだよね。 前にやった実装は、小数点以下2位固定だったから 1.23 を 123 にして計算してから、後ろ2桁の間にドットを入れて対応したけど 小数点以下の桁数が1.2とか1.234とかだったら面倒なんだよね。 bcコマンドとか呼び出せば簡単なんだが。 exec 3>&1; exec >&-; exec >&3 たまにこんなのを見ますがこれはどんな時に使うんです? ファイルディスクリプタ自体は理解しましたがfdの複製や切り替える目的が分からなくて cmd 2>err.txtは意識せず使えてますが >>252 不勉強なんで「3」ってfdは知らないんだけど、「>&」ってリダイレクトを 使うと書き込みじゃなくて切替になるんだけど、これを使うとエラー 出力を標準出力に切り替えて標準出力で両方の出力を得たりする ことができるです 「Command > FileName 2>&1」ってするとエラー出力の内容が標準 出力になってFileNameに両方の内容が書き込まれる 逆に「Command 2> FileName 1>&2」ってすると標準出力がエラー 出力になっるので、エラー出力でFileNameに書き込むことが出来る で、何に使うのかっていうと、「grep」なんかは検索結果は標準出力に でるけど「指定されたのはディレクトリだよ」みたいなメッセージは エラー出力に出される 両方の出力をみて処理したいとかの時にはこれで切り替えて標準 出力の内容を変数に保存しておいて処理するとかに使うです 例が雑でわかりにくいかもだけど、エラーと通常の出力を同じ出力で 使う方法ってことで、あとはスクリプトなんでアイデアしだいなんで >>252 はリダイレクトを知りたいんじゃなくて、fd=1 を 3 にコピーして 1 をクローズして再度 3 から 1 にコピーする意味 が何なのかを質問しているんだと思う。 結局もとのファイルに繋ぎなおすだけだよね。 一旦クローズするから flush されるとか?ならわかるんだが、実際どうなのかわからん。 ファイルディスクリプタに関しては 逆引き辞書が必要なんだと思う ○○をしたい時 → こうします。っていうやつ ファイルディスクリプタ(FD) 3番からは、システムが使うけど、ユーザーも使うことができる。 FD0 : 標準入力、FD1 : 標準出力、FD2 : 標準エラー出力 端末に、ls と打つと、 1. シェルが、lsコマンドのプロセスを起動して、それに、FD0〜2 を渡す 2. lsプロセスは、FD3 を使って、ファイル一覧を作って、FD1 に出力する 主なFD3 の使用方法は、標準入力を、ファイル・キーボードの2つで、切り替えて使いたい時 標準入力をファイルからにすると、キーボード入力が出来なくなるため、 一旦、標準入力(FD0)をFD3 にして、ファイルから入力して、済んだら元に戻す こんな事を一々、シェルスクリプトでやるよりも、Ruby でやればよい。 FD何番を使っているとか、意識せずにすむ exec 3<&0 < a.txt # FD3 から入力 while read LINE do echo "--- ${LINE} ---" done exec 0<&3 3<&- # 標準入力を元に戻し、FD3 を閉じる # 上のようにも書けるが、下の方が、標準入力のファイルディスクリプタ(FD)0 をいじらないので、安全 exec 3< a.txt while read LINE 0<&3 # FD3 から入力 do echo "--- ${LINE} ---" done exec 3<&- # 閉じる 「UNIX シェルスクリプト・コマンドブック 第2版、山下哲典」の、exec の説明の所に書いてある。 第3版には載っているかどうか、知らないけど CTRL+Cのトラップについて教えて 以下のスクリプトの時、実行してすぐにCTRL+Cを押すと #!/bin/sh set -e sigint() { echo sigint; } trap 'sigint' INT #trap 'echo $?' EXIT sleep 10 こんな感じでバラバラなんだけどさ dash・・・トラップできない。終了コード130 (ただしコメントアウトしてるEXITのtrapを有効にするとトラップできる) bash・・・トラップできる。終了コード130 zsh・・・トラップできる。終了コード130 ksh・・・トラップできない。終了コード130 (コメントアウトしてるEXITのtrapを有効にすると258と表示される。トラップできず) mksh・・・トラップできる。終了コード0 (コメントアウトしてるEXITのtrapを有効にすると0と表示される。トラップできる。) posh・・・トラップできない。終了コード130 (ただしコメントアウトしてるEXITのtrapを有効にするとトラップできる) yash・・・トラップできる。終了コード130 (コメントアウトしてるEXITのtrapを有効にすると386と表示される。トラップできる。) なんでこうなって、どれが正しい動きで、どれでも同じ動きさせるには、どうすりゃいいの? Ruby では、カスタムハンドラを定義した場合、終了しない。 デフォルトのままなら、Ctrl+C で終了する つまり、デフォルトハンドラから、カスタムハンドラへ付け替えたため sleep 7 #=> ここではデフォルトハンドラだから、Ctrl+C で終了する previous_handler = Signal.trap( :INT ) do puts "シグナルハンドラへ入った!" end print "previous_handler = " p previous_handler #=> "DEFAULT" sleep 7 #=> ここでは、カスタムハンドラへ付け替えたので、終了はしない それはシェルスクリプトも同じだろうな。上の終了しているのは set -e しているからじゃないのかな シェルスクリプトは子プロセスを起動していてシグナルを受けるのが子プロセスでが多くタイミング的に〜以下省略 > set -e しているからじゃないのかな それをわかってるから、サンプルコードにも入れてるんだけどねw 問題はそこじゃなくて、なんでシェル毎に挙動違うんだよ!? どれが正しいんだよ!?という話なわけで CTRL-Cを入力するタイミングが下手すぎるって話だろ まさか手入力じゃあるまいな? いやkill使うのは知ってる。それをどういう風に使えば、 手入力と全く同じことを再現できるのかという話だ。 2つの端末を使って一方で実行してから もう一方で(手入力で)実行するっていうのは 結局手入力してるのと変わらないし、 1つのスクリプトでkillすると、 それこそわけわからんことになる。 イベントハンドラ内でkillするか、違う場所でkillするか シェルによって挙動が違う Ruby では、 previous_handler = Signal.trap( :INT ) do puts "シグナルハンドラへ入った!" end print "previous_handler = " p previous_handler #=> "DEFAULT" # 自プロセスへシグナルを送ると、カスタムハンドラが呼ばれるが、終了はしない Process.kill :INT, Process.pid Signal.trap( :INT, previous_handler ) # 元のハンドラへ戻す sleep 7 #=> ここでは、デフォルトハンドラへ戻したので、Ctrl+C で終了する 「改訂2版 Ruby逆引きハンドブック」では、もっとややこしい記述をしてる シグナルハンドラはグローバルだから、 他のスレッドに変更されないように、Mutex で排他制御してる シングルスレッドでは、sleep 7、としてる間に同時に、 Process.kill :INT, Process.pid と、自プロセスの命令を実行できない マルチスレッドなら出来るのだろうが、マルチスレッド・プログラミングはややこしい! >>271 マルチスレッドのほうが楽だな。 それらをマルチプロセスでやってくれ。 子プロセスは自分で作成したものだけじゃなくて 既存のプログラムも使い、バックグラウンドプロセスも使ってみること zshの謎な挙動はこれが原因か? https://fumiyas.github.io/2013/12/05/trap-exit.sh-advent-calendar.html > でました、zsh の非互換! zsh はシグナルハンドラー※内で終了すると、 EXIT ハンドラーを実行してくれません。酷い。 (※この例では SIGINT のデフォルトのシグナルハンドラー) > こんな感じで bash, ksh, zsh には微妙な動作の違いがあったりするので、 ちょっと変わったことしようとするときは特に注意しましょう。 読みづらいなw $ zsh -c ' atexit(){ echo "Bye!"; }; trap atexit EXIT; trap "trap - EXIT; atexit; exit -1" TERM; kill -TERM $$ ' 全てのシェルで適切に終了処理をするって難しいな・・・ Ruby で、at_exit に、終了処理を書いておけばよい シェルスクリプトで、書く必要がない 時たま出来てしまうゾンビは何が原因なんだろう? kill -TERM 0 してるから全部死んでくれるはずなんだが・・・ あ、バックグラウンド処理とかしてる そしてCTRL-Cで強制終了した時の話 ゾンビだから消せなくて困る ゾンビは、子プロセスが終了して、 OS が、その終了コードをどう扱えば良いのか、わからないから、ひとまず保存している状態 普通なら、子プロセスの終了コードは、親プロセスへ渡されるのかな? ゾンビが生まれた時に、親プロセスがどうなっているのか? >>265 お前には言ってない >>266 タイミング的に子プロセスが受け取るのかシェルが受け取るのかってことなんだけどね。コマンドを実行中なのかシェルが実行中なのか set -e を使うからややこやしい、シグナルの基本をわかってないんじゃないんだろなとしか思えんけど。コマンドがINTシグナルで終了した場合、シェルが擬似的にシグナルハンドラ呼んでるっぽいかな(もしくは自らにINTシグナル出してるのかな?) 何したいのか知らんけど、set -e 使わずに、INTシグナルハンドラでexitすればいいんじゃないの >>279 その理屈はわかるんだけどねぇ まず必ずゾンビになるんじゃなくてたまになる。だからタイミングの問題 CTRL-Cを押した時になる。通常の処理では発生しない。 CTRL-Cのハンドラでは作業ディレクトリの削除を行っている。 ワーカー(& によるバックグラウンド処理)が複数ある。サブシェルを使ってるせいか 同じな名前のプロセスがたくさんいる。ワーカーを生成した後はwait(引数なし)を実行している。 ゾンビの存在は確認しているが、誰がゾンビになったのかその親が誰かはよくわかっていない。 (たまにしかならんので探しにくい)ただし内部で呼び出してるtrやmvがゾンビになったこともある。 CTRL-Cのハンドラでは作業ディレクトリの削除の他、多数生きてるワーカー(労働者)を 皆殺しにするためにジェノサイド(kill -TERM 0)を発動している。 ただし労働者を消した後に、労働者の作業場(作業ディレクトリ)も片付ける 必要があるので自分だけは死なないようにしている。(trap ':' TERM) 実際にはもっと複雑だけど、死なないのは自分だけなはずなんだけどな バグでゾンビになったこともあるので記憶が曖昧だけど (バグを修正した今は)zshだけしか発生しなくなっているかもしれない。 もしかしたらzsh内蔵のkillにバグがあって殺す順番とか 子供が生まれるタイミングで発生してるとか? でもまあなんだかんだでシンプルにしていったら ゾンビの発生率も下がってきたし諦めるかな うーん、おかしい。trってワーカー(バックグラウンドプロセス)の 中で使っているとはいえ、パイプの右側でしか使ってないんだが? 漏れにも、ゾンビになるプログラムとならないプログラムの、違いがわからない ゾンビになるメカニズムを検索してみれば? 「ゾンビになるメカニズム」で検索してみた 管理テーブルにデータが残ってるだけなら 消す方法(もしくは隠す方法)があってもいいと思うんだがねぇ >>284 wait()すりゃいいんだよ。 普通はinitが拾ってくれるんだが、誰にでも好き嫌いはあるということだろう。 >>280 >コマンドがINTシグナルで終了した場合、シェルが擬似的にシグナルハンドラ呼んでるっぽいかな(もしくは自らにINTシグナル出してるのかな 違うか。control-cでのINTシグナル送るやつの文献ってどこぞにあるかなあ Ctrl+C が、子プロセスやパイプラインのジョブグループに、 どのように伝達されていくかとか、難しい いろいろ間違っていた。訂正する。 まずCTRL-Cは関係なさそう。実は正常な動作でも(プログラム実行中に)ゾンビができることがあった。 ゾンビができると今は無限ループ状態になるので気づいたが、ちょっと前まではプログラムの構造上、 ゾンビを放置して正常終了していたと思う。zshではあまりテストしていなかったから気づかなかった。 バックグラウンドプロセスが関係あるかないかはよくわからない。 何回か動かしているがバックグラウンドプロセスを使用しない場合は今の所再現していない。 あとなんかWSLとのからみな気がしてきた。 速度が違うから断定は出来ないがLinuxだと再現しない。 今の所、WSL環境にて、zshで、バックグラウンドプロセスを使用し、 その中でパイプを使った処理を行うと、まれにゾンビプロセスができる。 >>286 シグナル一般の話ではなくてttyの話だったら、詳解Unixに載ってた気がするが、 当然そのくらいは読んでるよね。 >>287 ,289 なるほど すまん、読んでない。遠い記憶では読んでいたような気もするが忘れたので読んでない 再現コード出来た。このコード、なにか問題有る? これをWSL+ZSHで実行すると、人目につかず永遠とbcコマンドで1+1を計算し続け、 CTRL-Cで停止するときにbcコマンド含めたプロセスグループ全体をkillする(はず) これをやるとbcコマンドがゾンビ化する。(Linuxだとしない) #!/usr/bin/zsh int() { echo kill kill -TERM 0 echo killed exit 1 } trap 'int' INT trap ':' TERM worker() { while :; do echo '1+1' | bc > /dev/null done } for i in $(seq 16); do worker & done echo wait wait dash、bashでは再現しない。kshでも再現した。 いずれもWSLのみ。これもうWSLの問題だろ・・・ きっとWSLのバグをzshとkshが踏んじゃったんだな 次のWindows 10のリリースで治ってんじゃないですかねー もういいか Zombie zsh processes left behind that consume 8 % CPU each https://github.com/Microsoft/WSL/issues/3940 Killing a defunct zombie leaks the zombie process forever https://github.com/Microsoft/WSL/issues/3741 https://docs.microsoft.com/en-us/windows/wsl/release-notes#build-18267 Fix issue where zombie process may not be reaped and remain indefinitely. read -r text <<HERE printf [%s]\n it's a "s'm'a'l'l 'w"o'r"l'd" HERE $text ↓出力 [it's] [a] ["s'm'a'l'l] ['w"o'r"l'd"] この仕様、うまくすればなにかに使えそうな気がしている。 文法エラーにもならずevalとはまた違った挙動だ。 とゆうかどういう仕様なんだろう? $ cat b.pl #!/usr/bin/perl -w print("$_\n") foreach @ARGV; $ cat c.sh #!/bin/bash IFS=+ ./b.pl a b c ./b.pl a+b+c while read -r v ; do $v ; done <<EOF ./b.pl a b c ./b.pl+a+b+c EOF $ ./c.sh a b c a+b+c ./c.sh: 行 6: ./b.pl a b c: そのようなファイルやディレクトリはありません a b c $ # うん、なかなか面白いね。どうしてこうなるかは man に書いてあるよ。 $ # 簡単に言うと、単語の分割というのは最初に行われるものと $ # 変数が展開された後に行われるものがあるんだ。 $ シェルスクリプト(対話操作含め)が実行される手順って結構複雑な割に他の言語よりずっと単純だから 理論から実践(この場合はシステム処理とか?)への、かなり良い足掛かりになるよね。 http://www.sample/ {01..10}.jpg これが書かれたtxtを読み込んでブレース展開して出力する方法ないです? $ printf "%s\n" < foo.txt 適当にこうやっても上手く行かなくて eval $(echo -n 'echo '; cat foo.txt) とか? sh << END printf "%s\n" $(cat foo.txt) END echo "printf '%s\n' $(cat foo.txt)" | sh でよかった >>304 内側のリダクレクトが何かと思えば $(cat file)の変形があったとは 複数行も対応してるしこれなら行けそうですわ ごめん、もうちょっとシンプルに書けた。 eval echo $(<foo.txt) >>306 これいいね! ……正直,実際に使う機会は少なそうだけど シェルの処理をしっかり把握してないと思い付かない回答。 例えばさ、 bash -n -c 'a=(a b c)' ↑これはbashとして正しい文法だけどさ sh -n -c 'a=(a b c)' ↑これは文法エラーになるじゃん? 実行していなくても これみたいに、実行してないのにあるシェルではOKで 別のシェルではNGみたいな文法って他に何かしらない? >>308 君と似た例ではあるが; $ bash -n -c '%=a' $ sh -n -c '%=a' eval 'printf "%s\n" '$(cat foo.txt) これprintfをシングルクォートで囲まないと改行されないのね http://www.sample/01.jpgnhttp ://www.sample/02.jpgnhみたいな結果ばかりでちょっと悩んだ zsh使ってないけどこれはforの後の二重括弧に空白が必要だとかなんとか {には空白がいるのにfor((が通るbashの方が不自然なのか export -p と export の違いってなに? \n の処理をだれがいつやらかすのかってとこかな。printfにやらせたいprintfに \n のまま渡さなくてはという感じ eval printf "'%s\n'" $(cat foo.txt) eval printf '%s\\n' $(cat foo.txt) そもそもなぜ eval を使うのかというと、コマンドラインの解釈において ブレース展開がコマンド置換より前だから コマンド置換してからブレース展開するためには eval を使って解釈を最初からやり直す必要があるためで しかしながら printf と "%s\n" にはその必要がないのだから、つまり printf "%s\n" $(eval echo $(<foo.txt)) でいいんじゃないかな。 ダブルクリックで実行できるのとできないシェルスクリプトの違いって一体 whileとcaseで簡易メニュー作ってたんだけどダブルクリックしても画面に何も出ない上に 起動されたbashがCPUがかなり食ってた 無論端末から実行はしっかり通る ls結果を外部保存するような単純な奴はダブルクリックでも正常通りなんだけど >>311 マニュアル嫁 つーか実行すれば一目瞭然だぞ ……と思ってやってみたらexportはオプション成しで起動すると export -pと同じ動作をするんだね >>314 使ってるGUIシステムがX11なら x-terminal-emulatorなんかを使って仮想端末を立ち上げてからじゃないと メニューみたいな端末出力を必要とするものは期待した通りに動かないよ。 >>316 そうマニュアルに書いてあるだろう。なんのボケ?w 模範解答 export -p がどう表示されるかはPOSIXで規定されていますが、 export がどう表示されるかは未定義です。(同じとは限りません) つまり、exportがどうなるかはシェル毎に異なります。 http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#export 更にexport -pはbashではPOSIXに反してdeclareで表示されます。 これらは各シェルのマニュアルには書いていません。 ■ このスレッドは過去ログ倉庫に格納されています
read.cgi ver 07.5.5 2024/06/08 Walang Kapalit ★ | Donguri System Team 5ちゃんねる