シェルスクリプト総合 その26 [無断転載禁止]©2ch.net
■ このスレッドは過去ログ倉庫に格納されています
シェルスクリプトの総合スレです。 □お約束 ・特記なき場合はBourne Shell(/bin/sh)がデフォルトです。 bash/zsh/ksh/ashなどに依存する場合は明示しましょう。 Linuxユーザは/bin/shの正体がbashまたはdashなので特に注意。 FreeBSDユーザは/bin/shの正体がashなので注意。 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に逃げずにシェルスクリプトで処理するのが頭のいいやり方。 前スレ シェルスクリプト総合 その25 http://echo.2ch.net/test/read.cgi/unix/1439563321/ >>589 さん ありがとうございます。ちょっと英語で読解が難しいので時間を作って該当の箇所を読ませていただこうかと思います。 {2}の箇所を"2"に変更しました。 <の箇所をcatに変更しました。 非常に目に優しいくなりました。 読み込む箇所なので、怪しいと感じます。結果としては変わりませんでしたが、参照の箇所は興味がありますので読ませていただこうと思っています。英語で弱気になりますが^^; ありがとうございます。 >>593 さん すみません。確かにそうですよね。 初心者過ぎで逃げを当然にしてたバチがあたったようです。 吐き出したエラーは、 cp: /Volumes/Macintosh: No such file or directory cp: HD: No such file or directory などのファイルパスが、スペース区切りになってcp出来ませんでしたよというエラーでした。 ただ、検索に漏れた該当のファイルは何度めかにはヒットしますので上記のエラーとはならなかったということに。 spotlight特有のものだからと諦めるしかないのか・・・ これがひょっとしたら手がかりになるかもしれませんが、わたしの力では全く・・・ すみません、mdfindの検索結果のファイルパスが スペースで割れてしまってcpに渡されたということでした。たぶん^^; 解けました!ありがとうございます! ダブルコーテーションを%の箇所で囲うのではなく、 1行取り出した先でパイプして囲えば良いと思い以下を試したところ出来ました。 mdfind "kMDItemFSName == "${LINE}" || kMDItemDisplayName == "${LINE%.*}"" | awk 'NR==1' | sed -e 's/^\(.*\)$/\"\1\"/' | xargs -J % cp -p % "$1" 2>/Users/mac10/Desktop/out エラー出力素晴らしいです! ありがとうございました! mdfindとxargsに-0つけるのが定石だと思うけど、もう見てないかな。 >>575 今更だけど、あるんだよね。誰も教えたくなかったんだね。 ヒントくらい出すか……。でもあいつに教えたくないんだよなぁ。 卑屈だけど、気持は分かるだろ? パイプに名前(ry それ使うと出力側はこんな感じかな while :;do sed -e 's/\(.*\)/^[[32m\1^[[m/' np1 & sed -e 's/\(.*\)/^[[33m\1^[[m/' np2 >&2; done >>604 野暮な指摘だが、sedを使わない printf '\e[32m%s\[0m' "$(cat)" の方が分かりやすくね? つーか printf ってそういう「整形した出力」の為のコマンドだろうし。 >>695 ミスった… printf '\e[32m%s\e[0m' "$(cat)" だ。 こうすると "$(cat)" の部分で np1 を受けt[以下略] >>603 名前付きパイプ(mkfifo)はプロセスが2個あって 片方が出力側プロセス、片方側が入力側プロセスに 別れない限りストリーミングにすることができない (同一プロセスでは出力しながら入力ができないため) 今回の場合、標準出力と標準エラー出力の2つがあるから 出力側プロセス1個と入力側プロセス2個の合計3プロセスが必要になる つまり別プロセスとして起動しなければいけない もちろん出力の完了待ちのwaitも必要だし、作成したパイプの削除も必要。 特にCTRL+Cで中断された場合とか また万全を期してパイプ名が被ることも考慮してランダムな名前にしたい ここまで言えば名前付きパイプを使った方法は実装するのに行数がかかり 面倒な方法だと言うことがわかるだろう? また>>554 で書いたとおりbusyboxで動かす必要があるのだが、 そもそもbusyboxでmkfifoが存在しない場合もある ↑俺にとってはこっちのほうが重要 うわ。まだ居たのかこのキチガイ… まあ放置が一番いいな。俺のこのレスも彼を発狂させる原因になるやもしれんし。 まあ反論なく放置される(=俺の勝ち逃げ)という状況ってのが 俺にとっては一番であることには間違いないが で俺がレスしたのは、放置してないからだよ?w >>606 あ、しまった printf '\e' は GNU/Linux じゃないと動かないみたい。 Debian使ってんのがバレてしまったw FreeBSDとかでも動作させる為には printf '\033' とやる必要がある。 >>606 出力 A 正常 出力 B 異常 出力 C 正常 の時 それだとACBまたはBACと表示されないか? まぁそれで良ければ良いんだけど ガチでアレな奴が粘着してるな ここまで気持ち悪い奴は滅多に見ない >>553 exec > >(sed -e 's/\(.*\)/^[[32m\1^[[m/') exec 2> >(sed -e 's/\(.*\)/^[[33m\1^[[m/') 後は普通に処理を書けばおk どんだけ答え知りたいんだ あっちのスレいけよこっちはこっちで楽しんでんだから おいおい勘違いするな >>553 はbashやzshでのやり方を聞いてる。 POSIXの範囲でやりたいと言ってる俺ではない そういや>>616 で思い出したけど、 busyboxのsedってなんか動きがおかしいんだよね。 (echo 1; sleep 5; echo 2; sleep 5) | sed 's/a/a/' 例えばこれを実行すると、1が表示されるのは5秒後になる debianだとすぐに表示されるのに。一行遅れて表示される だからsedは今回の俺の用途には使えなくてreadを使ってる >>619 Ubuntu ではおかしいみたいですね。 Debian と openSUSE の busybox では記述通りの動きでした。 >>620 WSL上のUbuntuは問題なかった。 busyboxはビルドによって色々変わるだろうけど よく分からんね > openSUSE の busybox では記述通りの動きでした。 もしかして、sedはbusyboxじゃない方のsedになってない? WSL上のUbuntuに入れたbusyboxのsed ↓つまりこれを実行するとやっぱり5秒後に1と表示される (echo 1; sleep 5; echo 2; sleep 5) | busybox sed 's/a/a/' やっぱりbusyboxが実装してる簡易版sedの問題な気がする まあもともとbusyboxってそういうものだし とりわけ騒いだりはしないけどさ >>622 >>620 は busybox ash でシェルを起動して確認しています。 busybox sed 's/a/a/' にすると Debian も openSUSE も Ubuntu と同じ動作になりました。 おーほんとだ。Busybox v1.22.1 on Debianでも同じような動きになる。 ここまでハッキリしたバグに遭遇したの久し振りだわ 単に離れてただけかもしれんが なにやら興味がある人がいるようでw なんで俺の用途で使えないかというと、例えばこんな感じに ユーザーのインタラクティブな入力を変換して出力したいから ↓ >(実際には画面に表示されない) の行がユーザーの入力 $ sh | sed 's/a/a/' > echo 1 > echo 2 1 > echo 3 2 見ての通りユーザーが入力したコマンドの結果が一つ遅れて表示される sedのよくあるユースケースでは問題ないんだろうけどね >>626 挙動が変わるツールは珍しいなと思いました。 busybox ash の中で sh | sed 's/a/a/' とすると、 Debian (v1.22.1) まとも Ubuntu (v1.22.1) 遅れる openSUSE (v1.21.1) まとも(sh プロンプトが表示される) CentOS (v1.15.1) まとも(sh プロンプトが表示される) Windows (v1.29.0) 遅れる でした。 ビルド時に引いているライブラリの差異なのでしょうか... バッファリングが影響してそうなのかもしれないけど 正規表現の実装の都合な気もする。 はたまたカーネルが関係してるのかシェルの設定でなんかあるのか 正直、そういう違いが有るんだね。気をつけておくよと 事実を受け止めるぐらいでで深追いする気力はないw 話変わるけど、何もしない関数の定義、 foo() : もしくは、echoするだけの関数の定義 foo(): echo foo この書き方ってPOSIX準拠だよね? bashやzshではエラーになった >>628 foo() echo foo ならzshは理解するぞ Bourne shell系はfoo() any-compound-commandだけ理解して foo() any-commandは理解しない >>628 POSIX準拠なのかはよくわかりませんが、sh ならば foo() foo1() echo "$1" で、sh でも bash でも動かすなら foo() { :; } foo1() { echo "$1"; } でいけると思います。 訂正 × foo(): echo foo ○ foo() echo foo >>629 ごめん、zshでは試していなかった。 今zsh入れてたマシン壊れてるんだったw 別の環境にzsh入れたらたしかに動いたね dash、ash、zsh では動いた bashだけ動かなかった func() : ↑これ確かにシェバンを #! /bin/sh にすると通るけど #! /usr/bin/env bash にすると撥ねられるな。 http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_09_05 一応現行POSIXのシェル関数の定義はここに書いてあるけど、func() : は恐らく適合してるな。 多分bashの文法チェックが少しばかりおせっかいすぎるんだろう。 でもPOSIXに準拠した記法なのにエラーになるって嫌だなぁ あれ。yashでも「syntax error: a function body must be a compound command」って撥ねられるわ。 yashはかなり厳密にPOSIXに従ってる筈なんだけど… またちょうどよくシバンの話がw シェルスクリプトのファイルを直接実行するのではなく ライブラリとして他のスクリプトから読み込むだけの場合 シバンいらないよね? またその場合の拡張子ってどうしてる? シンタックスハイライトとか自動で適用させたいんだけど 余計なものはできるだけ排除したい >>632 そうなんだよね。あと > fname ( ) compound-command [io-redirect ...] ここにio-redirectが書けたのがびっくり どういう時に使えば良いんだろうか? >>635 俺は未インストールコマンドの処理に使ってる check_command() { type "$1" > /dev/null 2>&1 || { printf '%s%s\n' \ "$1" 'をインストールして下さい。' exit 1 } >&2 return $? } check_command "curl" こうするとエラーメッセージが標準出力に出ないからパイプ繋いでてもおかしなことになりにくい。 もっとも |& ←みたいなパイプなら無理だけど、そもそも標準エラー出力ごとパイプに使うなんて稀だろうという推測。 >>636 いや、そうではなくて関数定義の最後に書けるんだなーって話 その例で言えば、こういう書き方ってこと (関数全体を別の所に出力したいときには便利か、うーん使うかな?) check_command() { type "$1" > /dev/null 2>&1 || { printf '%sをインストールして下さい。\n' "$1" exit 1 } } >&2 # ついでにどうでもいい所を俺の趣味で変更したw # exitもreturnに変えたい。もしくはexit_if_command_not_foundみたいな関数名にしたい > もっとも |& ←みたいなパイプなら無理だけど、そもそも標準エラー出力ごとパイプに使うなんて稀だろうという推測。 /dev/ttyに出力するって手もあるよ $ (echo stdout-a; echo stderr-a >&2; echo tty-a >/dev/tty) |& sed 's/a/b/' tty-a stdout-b stderr-b >>633 yash覚えた 最低限機能しかももってないと思われるashで動けば Bourne Shell 系全部でうごくだろうと思っていたから そういうこともあるんだなーって思った >>637 あ,そういうことか。勘違いしてたわw それはちょっと使い道思い付かん ところで, return $? ↑これ消した理由なに? C言語をやってるせいか関数が終了ステータスを返さないと不安で仕方無いんだけども, シェルスクリプトだと要らないのかな。今まで特にreturn行のせいで不具合が発生したこともなかったけれど。 >>639 何も書いてなければ、その時点の$?がそのまま返るだろ? > C言語をやってるせいか関数が終了ステータスを返さないと不安で仕方無いんだけども, Ruby(最後に評価された値を返す)やってるとreturnなんて書かないんだがw > 今まで特にreturn行のせいで不具合が発生したこともなかったけれど。 まあ不具合は発生しないだろうね。 関数の最後でなにもしないなら、その時点の $? が返る所を $?を取り出してreturnの引数で$?を返すようにしただけだからw Cとか化石みたいな言語使ってる人って無駄が多いよね 生産性悪w そういうこと言う奴って大体Cが出来ないコンプレックス抱えてるんだよなぁ Cはハードに近いところを表現するのに適してるから絶対に無くならないけどね。 化石だけど生活には欠かせない燃料みたいなもんかな。 Cで書かれてるシェルのスレで否定しちゃうのはちょっと痛いね。 俺はCを否定してないぞ。C以外を使っていれば returnしなくていい言語だってあることを知るだろうし、 returnを書くことに拘る必要はないってことだ >>640 ruby使ってたってreturn書くことあるだろ implicitとexplicitを状況に応じて使い分けることが大事 >>649 Cに対するコンプレックス同様 Rubyに対するコンプレックスも見苦しい >>647 returnを省略できる場合に、returnを書くことはないよ 話をぶった切ってすまんが、なるべく依存関係が少ない・かつインタラクティブがある程度機能的なPOSIX互換シェルって何があるかな。 ksh98とかyashとかは使ったことあるけど、ああいう感じでもうちょい開発が盛んなやつとか知らない? 連続足し算だけど #!/bin/bash while true do add=expr 0 read x add=$(($add + $x)) echo '----------' echo ' ' $add done でできるが line 5: 0: command not found 1 ---------- 1 ./tasizan-renzoku.bat: line 5: 0: command not found 2 ---------- 3 ./tasizan-renzoku.bat: line 5: 0: command not found と 気色悪い。 どうすれば正解なの? すごいね、以下でエラーがなくなった。 #!/bin/bash while true do add=(expr 0) read x add=$(($add + $x)) echo '----------' echo ' ' $add done a=0 while read x; do a=$((a + x)) echo ---------- echo ' ' $a done ありがとう。 合計を外側で定義することがわからなかった。 こうなると 電卓より便利! また頭がおかしいのがわいてきた UNIX板荒らさないでほしい コマンドにローマ字で名前付けるやつは多かれ少なかれキチ成分が入ってる (経験からくる偏見) for i in `seq -f %02g 1 10` do echo ${i} done このfor文の中で01の時に1、02の時に2を指定する方法ってありませんか? 簡潔に言うと先頭の0を取ったものを使いたいです >>662 どうしてデバッグが楽なのか知らんが、 少なくともprintfデバッグすると 終了コードが0に変わるからデバッグしづらいな >>664 2桁と決まっているなら echo "${i##0}" 逆にしてこっちのほうが楽だと思うが for i in $(seq 1 10) do printf "%02d\n" $i done 拡張POSIX準拠らしいけど echo {1..10} {01..10} arch linuxだと普通のshでも展開してくれる >>668 > arch linuxだと普通のshでも展開してくれる してくれなかったぞ > 拡張POSIX準拠らしいけど 拡張POSIXってしう仕様があるの? POSIXを拡張したもので、POSIX非準拠って意味だと思ってたんだけど? シェルスクリプトってさ、POSIXが標準だけど 実質bashがデファクトスタンダードって考えて良いのかな? zshやfishを使っていてもbashはインストールされていると考えていい? いや、あるコマンド作ろうと思ってるんだけど、 基本はPOSIXで動くようにするけど、bashがインストールされていれば 拡張機能が使えるようになる。という仕組みは ほぼすべての人が拡張機能使えると考えて良いんだろうかなって思って >>673 bash前提はだめ。 BSD系にはデフォルトで入っていないし、後から入れてもパスが違う。 >>671 ごめん /bin/shのバージョン確認してみたら GNU bash, バージョン 4.4.19だった >>674 いやbash前提じゃないんだ。POSIX シェル前提。POSIX シェルだけで動く。 だけどbashがインストールされていれば拡張機能が使える その拡張機能っていうのも、本質的な機能じゃなくて なんていうかな、同じコマンドで実行結果も同じだけど情報が詳細に取れるって感じ BSD系といってもMacはデフォルトでbashになったのは知ってる。 パスに関してはシバンではなくbashコマンド経由で実行すれば良いと思ってる (切替可能なようにするのでどっちみちシバンには頼らないと思うし) >>675 うん、たしかCentOS系はbashへのシンボリックリンクになってたはず Debian系はdashなので拡張POISXは使えない POSIX規定外のことをPOSIX拡張って書くのは誤解のもとだからやめた方がいい。 伝統的にシェルにはなくてPOSIXで増えた機能のことをPOSIX拡張とよぶことがあるので、意味が真逆。 可搬性を考えるとPOSIX準拠で書く癖をつけた方が 自分のためになるなあ ★★★The● best way to eliminate too much gap between rich and poor, is to decide the tax● rate of the progressive tax in the referendum(Root Tax).★★★ この掲示板(万有サロン)に優●秀な書き込みをして、総額148万円の賞金をゲットしよう!(*^^)v ● http://jbbs.livedoor.jp/study/3729/ →リンクが不良なら、検索窓に入●れる! POSIX準拠で書くのは結構つらいので デファクトスタンダードであるbash機能のみで書くといいよ >>676 いっその事 ps -p $$ -o comm= でシェルを見て処理を分けるとか >>682 見分け方は本質的なところじゃないんで 俺にとってはどうでもいい話だけど、 シェルの判定ではなくて機能チェックで見分けるよ ブラウザをUserAgentで判定するのではなく 使いたい機能が使えるかどうかで判定するのと似たようなやり方ね > ps -p $$ -o comm= ちなみにそれcygwinではエラーになった >>683 bash や zsh の機能を多く使うならば、その都度機能が動くかどうか判定するより、 起動シェルを見て分岐したほうが手間がないという意味合いで書きました。 cygwin の ps は -o オプションは無いのですね。失礼しました。 freebsd の環境で hoge.sh に ps -p $$ -o comm= と書いて、 /usr/local/bin/bash ./hoge.sh とすると、bash と表示されます。 (debian とかの ps でも ok) cygwin の /bin/sh は /bin/bash なのでシェルを見るよりその都度使用する機能を判定するほうがよさそうですね。 > > ps -p $$ -o comm= > ちなみにそれcygwinではエラーになった マジで!? POSIXでも定義されてるんだけどなぁ 壊れた動画探しに ffmpeg -i input -f null /dev/null 2>&1 | grep -m 1 -Ii error ffmpeg -i input -f null /dev/null 2>&1 | grep -q -i error とやったのですけれど、grepにヒットしてもffmpegの動画読み込みが止まりません。 grepにヒットしたらffmpegを止めるにはどうすればいいのか。 いいアイデアはないですか。 ffmpeg -xerror は使えないんだっけ ‘-xerror (global)’ Stop and exit on error bashがどうしても使えない化石サーバは廃品回収へ 新Mac板から来ました。 カレントディレクトリ内にaacファイルがあれば、mediainfoでHE-AACかLC-AACか調査して、 l-smash muxerを使ってHE-AACとLC-AACでは別のコマンドにてm4aに詰め込みたいです。 以下のままだと、aacが無い場合は ----- aacファイルはありません. ----- iTunes MP4 muxing mode ./test.sh: 3 行: 27777 Segmentation fault: 11 muxer -i $file 〜 と表示されてしまいます。 AACファイルがない場合はmuxerのコマンドに進まないようにするにはどう書くといいんでしょうか? 続く 続き #!/usr/bin/env bash for file in *.aac; do if [ -e $file ] ; then # aacファイルが存在する場合 mediainfo $file | grep '^Format profile *: LC$' >/dev/null 2>&1 #es=$? else echo "-----" # aacファイルが存在しない場合 echo "aacファイルはありません." fi #------------------------------------ # HE-AACだった場合 if [ $? = 1 ] ; then echo "-----" muxer -i $file?sbr --file-format m4a -o ${file%.aac}.m4a fi #------------------------------------ #AACの場合 if [ $? = 0 ] ; then echo "-----" muxer -i $file --file-format m4a -o ${file%.aac}.m4a fi # .aacで終わるファイル名だけど、HEでもLEでもどちらでも無い場合はどうやるんだろうか done $1は本当に直前に実行したのコマンドのステータスしか入らないから注意 ifで比較する前にecho $1で何が入ってるか確かめてごらん それをふまえて論理構造組み直しな 「AACの場合」の前後の fi と if ... の2行を else に置き換えた上で、mediainfo コマンドの直後に 「HE-AAC だった場合」以降の if/else 文を移動、ではだめかな。 $? はすぐに別のコマンドの結果を格納してしまうので、 . mediainfo ... . MEDIAINFO_RET=$? . ... . if [ $MEDIAINFO_RET = 0 ] ; then ... みたいにコマンド実行直後に別の変数に回収してみるといいかもね。 >>687 ,>>689 ありがとう 早速試してみる ■ このスレッドは過去ログ倉庫に格納されています
read.cgi ver 07.5.5 2024/06/08 Walang Kapalit ★ | Donguri System Team 5ちゃんねる