シェルスクリプト総合 その27
■ このスレッドは過去ログ倉庫に格納されています
シェルスクリプトの総合スレです。
□お約束
・特記なき場合はBourne Shell(/bin/sh)もしくはPOSIX準拠の互換シェルがデフォルトです。
bash/zsh/ksh/ash/dash/yash/poshなどの専用機能に依存する場合は明示しましょう。
Linuxユーザは/bin/shの正体がbashまたはdashなので特に注意。
FreeBSDユーザは/bin/shの正体がashなので注意。
・POSIXについてのリンクは https://en.wikipedia.org/wiki/POSIX にまとめられています
最新の仕様はこちらへ http://pubs.opengroup.org/onlinepubs/9699919799/
(左上の「Shell & Utilities」 から参照することができます。)
・v7 shに一番近くて、現役(?)のshは、OpenSolaris由来のheirloom sh。
http://src.illumos.org/source/xref/illumos-gate/usr/src/cmd/sh/
http://heirloom.sourceforge.net/sh.html
・csh/tcshのシェルスクリプトは推奨されません。
(理由は「csh-whynot」でググれ)
・UNIXにはシェルスクリプトに便利な小さなコマンドがいろいろあります。
manや参考リンクを見ましょう。
aproposないしはman -kでそれらしい単語による簡単な検索もできます。
・シェルで使えるワイルドカード等は正規表現ではありません。
正規表現の話題はスレ違い(正規表現スレへ)
・シェルスクリプトのことをシェルってゆうな
□初心者へのアドバイス:
・適した道具を判断するのも頭の重要な使い方。シェルスクリプトよりも
awkまたはperlの方が適した処理にはそちらを使いましょう。
・知らないコマンドが出てきたらmanを引きましょう。
・思い通りに動かないときは、まずは sh -x でトレースしましょう。
□回答者への注意事項:
・シェルスクリプトでの処理方法を質問しているのに、よくわからずに
「そういうのはperl使いましょう」と回答するのはやめましょう。
安易にperlに逃げずにシェルスクリプトで処理するのが頭のいいやり方。
質問に対して問題が間違ってるといちゃもんをつけるのもやめましょう
前スレ シェルスクリプト総合 その26
https://mevius.5ch.net/test/read.cgi/unix/1489979246/ POSIX shで絶対値をなるべく簡単に扱いたいんだけどいい方法ありますかね
exprコマンドにabsとかがあればよかったんだけども >>571
入力側のリダイレクトって読みにくいので、自分もcatで書くかも >>575
いやでござるwww
>>576
マイナスだけでいいなら
echo ${a#-}
プラスも考慮するなら
echo $((${a#-})) >>576
こんなのどうだろう
$(((0 < a)?a:a * -1))
(aに値を代入) なんで俺が短く書いたのに、わざわざ冗長なコード書くかね?
しかも三項演算子を使ってもっと短くかけるし
$(((0 < a)?a:a * -1))
$((a>0?a:-a))
$((${a#-}))
${a#-} >>581
おまえのコードは本質的じゃない
彼が望むのは「絶対値」であって「マイナスを除いたもの」ではない
OK?
分かったらひっこんでろ低能
もしこれに反論があったら「分かってない」ことになるからな? >>582
わかってないのはお前では?
つーか、その反論されたら困るからって
「反論したら俺のかちー」みたいな言い方やめた方がいいよ
恥ずかしいw
俺は反論したから、さあ、次はお前が反論する番だ もう消えろお前ら
このスレに相応しくない
なんだよ最近のこのスレの雰囲気最悪じゃねーか
長文ダラダラ返信長々と最後にレスしたほうが勝ちみたいな古い争いしやがってからに >>577
簡潔に書きたいというお題じゃなかったのか >>577
<をどこに書いてもいいことはあまり知られていない。
</etc/password grep /bin/bash | cut -d: -f1 >>577
そりゃあんたの頭のレベルが低いからだと思うよ >583の脳内では全く論がない噛みつくだけの行為も反「論」になるらしい
これもう日本語が分かってないってレベルじゃないな
ただの小学生だわ 小学生なら簡単に構ってちゃんになりそうなのはわかるな。もう構うなw GNU grep なら
$ grep -Po '^.+?(?=:.+:/bin/bash$)' /etc/passwd >>591
論じゃなければ、何か言い返せよって言うだけの話だけど?
ほんと本質じゃないどうでもいい所にしか反応しないのなw >>595
違うと思うぞw
でもあんたはそう思ったから、書き込んだんだよね レスしなきゃ負けると信じてるみたいだからしょうがないね $ cat <<. <<.
1AAA
.
2BBB
.
とやると
2BBB
とだけ出力されるんだけど、これどういう理屈か分かる?
標準入力ってヒアドキュメントでさえ上書きされる仕様なの? strace で見ると 2BBB だけ read してるな(1AAA は無視)。 >>598
なるほど。だから「さいごに〜」とか話に全く関係ないことを言い出したのねw
>>599
ヒアドキュメントって標準入力として読み取るものでしょ?
そこは何らおかしくない
cat < /proc/loadavg < /proc/uptime
ってかいて、/proc/uptime からしか読み込まないのと一緒だと思うよ >>595
0x03e8 ばんさえとれればあなたのしょうりです。 >>601
なるほどね
$ somecmd < a.file < b.file
↑これでb.fileしか読み込まれないのも(やったことなかったから)知らなかった。
ありがとう リダイレクトは引数じゃないからね
実質これと同じわけだし
exec </proc/loadavg
exec </proc/uptime
cat >>593
を〜、grep -oで切り出しできるのね
久々にこのスレで参考になりました コロンを含むディレクトリを$PATHに登録した場合ってどういう挙動になるんだろう findでexecオプションの引数のあとにシェルに渡すパイプを付けるとexecに渡したコマンドがシグナル13パイプ破壊を出してくるんですけど
どうにかなりませんかね。
今のところ/dev/nullに標準エラー出力を捨てることで解決してるんですけども。
find . -exec basename \{\} \; | head
↑これで再現するはずです。
解決するときはできればPOSIXの範囲でやりたいです。findのGNU拡張で解決できるならそれでもいいんですが
メインPCがOS Xなので、最低でもBSD拡張、さらに言えばPOSIXに限定してほしいです すいません。 FreeBSDは再現しない。
CentOSは再現した。
対策は後で考える。 なにか最近やけに POSIX にこだわってる奴が多いが同一人物か? >>613
単純にPOSIXの価値というかシェルスクリプト全体の有用性が見直されているだけでは
たとえば*BSDのスレでGNUライセンスに拘ったレスが連続するのはおかしいが
BSDライセンスを重視するスレがたくさんあっても別におかしくはないだろう パイプでなのでfindとhead が同時にプロセスとして存在
findが標準出力に出力するとパイプを通して/パイプとして繋がってるheadの標準入力に入力として
headが目的を達して終了=パイプが無くなる、だがしかし、findは出力を続けようとし出力しようとしたらパイプが壊れてるうううっ
普通何もしなくても、パイプが損失したらSIGPIPEが飛んできて(強制)終了するんだけど(フィルタとしてもなUNIX的な望ましいデフォルト動作)、なぜかSIGPIPE無視して続けようという謎動作?
findとheadが直接は繋がっていなくてかもしれんが。パイプの送出側がSIGPIPEを無視って謎動作なのは変わらないかな >>615
basenameが標準出力につながってるだけだから、findはwriteしないのでSIGPIPEを受け取らないよ。
basenameが事故死したのをfindが報告してるだけ。
というわけで、basenameが事故死したらfindを続けるのをやめるようにしてみた。
この方が無駄にbasenameを続けるよりよかろう。
find /var \( -exec basename {} \; -o -quit \) | head
ただし、最初の事故死についてだけはfindがおせっかいに報告してしまう。
あとはまかせた。 >>616
そのへんが実装によりちょっと違うってとこなのかなあ。出る出ないは >>613
自分側で「なにか違って」動かなかったらめんどくさいってだけじゃないの、単に CentOS$ strings /bin/find | grep -i signal
signal
%s terminated by signal %d
FreeBSD$ strings /usr/bin/find | grep -i signal
なんもなし
以上、findのおせっかい度の差。 すまん間違えて送信しちゃった
$ find /etc -exec sh -c 'basename {}' \; | head
これでどうだろう。
-quitオプションはPOSIXの範疇ではないけどこれはPOSIXに準拠してる
ちなみに>>610のコマンドラインはDebian GNU/Linuxのfind 4.7で再現した。 >>619,620
なーるほどっ
ww
なるほどっ、なっとく >>621
ん? それSIGPIPEは回避できるけど別の問題が発生しない?
「basename: 余分な演算子 XXX」←みたいに怒られるんだが
あと
$ find /etc -exec sh -c 'echo {}' \; | head
↑これをやるとやっぱりSIGPIPEが出されるようだ。 >>613
どこかの先生が課題にそう書いてるんだろう。
ちゃんと調べないで持ってくるバカ学生が多いんじゃないの。 >>610
>findでexecオプションの引数のあとにシェルに渡すパイプを付けるとexecに渡したコマンドがシグナル13パイプ破壊を出してくるんですけど
この動作は、POSIX的にはどうなの?
まずいというならPOSIX的にどうまずいの? find . -exec basename \{\} \; | { head; cat >/dev/null; } -execにこだわりがないのであれば、
find . -print0 | xargs -0 -L 1 basename | head
今度はxargsがお節介メッセージ出すけど、findはheadが終了したら終了する xargs(1)に-0オプションはない(POSIX厨) findにも-print0は無いけどな。BSDにもあるからいいんじゃね find . -print | xargs -n1 basename 2>/dev/null | head >>634
こういうPOSIXにやたらこだわってるのって
なにかの精神障碍があるんじゃないの?
一度そういう病院で診てもらえ。 >>616
find . -exec sh -c 'trap "exit" pipe; basename {}' \; -o -quit | head >>638
試してないけど、trapせずにbasenameのあとにexitするだけでだめなん? find /etc -exec basename \{\} \; |& head
これでエラーも出ず余計な出力も引っ掛らなかったんだけど
理屈が分からん
|& は標準出力と標準エラー出力両方を通すはずなので
SIGPIPEのエラーが出力されるはずだがgrepしても見当らない find自身がSIGPIPEで終了してんじゃない
実行時間も短くなってるし >>641
すいません。それどうやって確かめたらいいですかね Linux なら strace で見ると分かる
$ strace -f bash -c 'find /etc -exec basename \{\} \; |& head' stderrが(標準出力)のパイプになりの、そのパイプが無くなり、find自身がエラーメッセージをそれに書き込もうとしてSIGPIPEを受けるってとこか
find . -exec basename {} \; -o -print | head
としても同じように終わるってとこで >>640
だれかこれをmacOSでやってくれない?
あれは確かSIGPIPEを受けとらないから
GNU findと違ってこの書き方だと不具合が起こりそうだ >>646
>あれは確かSIGPIPEを受けとらない
いや、それはないだろう。単に>>621の違いじゃないの
macOS Sierra標準のbashはまだ |& をサポートしてないヤツみたいなので(??)、2>&1 | としたが同じくfindは終わる ああ、|& は元々はzshのなのか(?)
macOS Sierra標準のzshでは/でも、>>640のままで特に何も問題なく終わった >>649
|&はcsh由来。zshはパクっただけ。 それはPOSIXですか?POSIXじゃないのですか? ところで俺のPOSIXを見てくれ。こいつをどう思う? まあPOSIXじゃないので質問者の要請は満たしてないよね
俺が提案するとしたらexecは使わず
find . | xargs -I @ basename @ | head
↑これ。 それじゃあかんだろ。xargsのオプションが足りない 俺がやるなら xargs -I には {} を 指定するがな
@というのは見たことがない 社内規約かなにかかな? この問題って本質的には、 find は /etc の下の全部のファイル(10以上)を返すが、
head は 10行で打ち切ってしまうという矛盾にある。
そこは目をつぶるって方針なんだから、最初に書いてあったstderrを捨てるって
方法で正しいと思うよ >>658
xargs: basename: terminated by signal 13 って表示されちゃう
>>661
俺は @ しか使ったことがない >>662
バッカこれはどっちも形容詞だよ
だからネタとして成立してんじゃん コマンドの重複を数える(つまり$PATHに登録され実行可能なファイルの重複を列挙する)一番短い方法をってなんでしょう。ただし確実に動作しかつ可搬であることが条件です。
僕が考えたのは
$ echo $PATH | tr ':' '\n' | xargs -I @ find @ \( -type f -a -perm -+x \) -exec basename \{\} \; | sort | uniq -c
です。 basenameにしたらファイル名じゃなくなるじゃん >>668
?
もしかして-type fが見えてないだけ? パスの中に空白が入ってる or PATHの中身が多すぎたらおそらくアウト
( IFS=:; find $PATH -type f -a -perm -+x ) | sed 's|.*/||g' | sort | uniq -c
( IFS=:; for i in $PATH; do find "$i" -type f -a -perm -+x; done ) | sed 's|.*/||g' | sort | uniq -c できればsedでやりたいことなんですが
aaa
<<
bbb
>>
もしくは
aaa
<<bbb>>
というようなファイルがあったとしてaaaの次行から「>>」を含む行までを読み出したいです。
(aaaが存在する行はすでに具体的な数値で判明しています; ここでは42行目とします)
特に二番目の場合には sed -n -e '43,/>>/p'とやると43行目に「>>」があるのに見つけてくれません。
なにか手助けをおねがいします。 >>671
sed -e '42,/>>/!d' -e 42d あれんじ
sed -e '43,$!d;/>>/q' ■ このスレッドは過去ログ倉庫に格納されています