シェルスクリプト総合 その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/ >>194 わざわざまた出てくるとかどんだけプライド高いんだよ w >>202 拗らせるだけだからもう触んな。わかるやつにはわかってるから Cからawkだとつまらない解になってしまうな。 awk '{for(i=2;i<=$0;i++){ if(i==$0){print $0"は素数でした 。"} else if(($0%i)==0){print $0"は素数ではありません。"i"で割り切れます。";break; }}}' <<< "$(read -p "2以上の整数をキーボードから入力してください。" res ; cat <<< "$res")" >>205 いい加減にしろ。うざいって言われてるのはお前だってわかってないのか? curl -s "http://hage.com.json" ; | jq -r '.main | .detail_list[] | .file_list[] | .date, .file_title, .file_name' これだと、date と file_title とfile_name の内容が表示されるんですが、 detail_listと同じ階層にあるnavi_nameの内容も表示させたい場合はどう書けばいいですか? よろしくお願いします。 >>209 とくにこだわりがないのであれば jq じゃなく parsrj 使えば? aaa=(888 犬 `date +"%Y%m%d"010000 -d last-sunday`) bbb=(777 猫 `date +"%Y%m%d"150000 -d last-Saturday`) ccc=(666 鳥 `date +"%Y%m%d"000000 -d last-friday`) for hoge in "$aaa" "$bbb" "$ccc" do if [ -e ~/${hoge[1]}_${hoge[2]:0:4}_${hoge[2]:4:2}_${hoge[2]:6:2}.mp4 ]; then exit 0 else ffmpeg -i ~/output/${hoge[2]}-${hoge[0]}.aac ~/${hoge[1]}_${hoge[2]:0:4}_${hoge[2]:4:2}_${hoge[2]:6:2}.mp4 fi done こんな感じのスクリプト書いたのですが、配列が展開してくれません。 どうすれば変数に入れた配列が機能するでしょうか アドバイスお願いします。 >>210 jqにこだわりはないが、 parsrjなんて誰も使ってないものは使いたくないなw >>189 状態ってなんだよwwwって話だよなあ 頭の悪い人は理解できないみたいだけど やりたいこと想像してベタにやってみたけど printf "%s %s %s\n" ${aaa[@]} ${bbb[@]} ${ccc[@]} | while read hoge0 hoge1 hoge2; do if [ -e ~/${hoge1}_${hoge2:0:4}_${hoge2:4:2}_${hoge2:6:2}.mp4 ]; then exit 0 else ffmpeg -nostdin -i ~/output/${hoge2}-${hoge0}.aac ~/${hoge1}_${hoge2:0:4}_${hoge2:4:2}_${hoge2:6:2}.mp4 fi done ...て、ほぼ配列じゃなくなっちゃったは >>217 あとは、そのbash依存の文字列の〜文字目をとってくるってのをなくそう っていうかdate使って%Y_%m_%dとかでいいだろと よくいる偉そうにしたいのが主な目的なのがわいてる感じ そういう言葉でしか言い返せないのな 悔しかったら技術で勝負しろ どこに勝負要素があるのか分からない しかし最近汚いコードがばらっと貼り付けられまくるのは同一人物なのか? 身に覚えがなかったら勝負とか言わないよなあ。てか、勝負ってw なにか偉そうにしたい/マウントとりたいのがありありだな >>221 違うんじゃね。汚いとか言いだしたらきりがないぞな。言うなら整形して上げたほうが意味あるんじゃね 年月日を配列でw printf "%s %s %s\n" ${aaa[@]} ${bbb[@]} ${ccc[@]} | while read hoge0 hoge1 hoge2; do fuga=(`echo $hoge2 | sed 's/^\(....\)\(..\)\(..\).*/\1 \2 \3/'`) if [ -e ~/${hoge1}_${fuga[0]}_${fuga[1]}_${fuga[2]}.mp4 ]; then exit 0 else ffmpeg -nostdin -i ~/output/${hoge2}-${hoge0}.aac ~/${hoge1}_${fuga[0]}_${fuga[1]}_${fuga[2]}.mp4 fi done からの〜 printf "%s %s %s\n" ${aaa[@]} ${bbb[@]} ${ccc[@]} | while read hoge0 hoge1 hoge2; do set - `echo ${hoge2} | sed 's/^\(....\)\(..\)\(..\).*/\1 \2 \3/'` if [ -e ~/${hoge1}_$1_$2_$3.mp4 ]; then exit 0 else ffmpeg -nostdin -i ~/output/${hoge2}-${hoge0}.aac ~/${hoge1}_$1_$2_$3.mp4 fi done 元のソースが汚いと修正も面倒だなとw まず一旦ループと変数をやめる if [ -e ~/犬_2018_06_06.mp4 ]; then exit 0 else ffmpeg -i ~/output/20180603010000-888.aac ~/犬_2018_06_06.mp4 fi if [ -e ~/猫_2018_06_06.mp4 ]; then exit 0 else ffmpeg -i ~/output/20180603150000-777.aac ~/猫_2018_06_06.mp4.mp4 fi if [ -e ~/鳥_2018_06_06.mp4 ]; then exit 0 else ffmpeg -i ~/output/20180603010000-666.aac ~/鳥_2018_06_06.mp4.mp4 fi つぎに、変数に入れ直す そして書き込もうとしたらNGワードとか言われたから ついでに関数にする infile=~/output/20180603010000-888.aac outfile=~/犬_2018_06_06.mp4 output "$infile" "$outfile" infile=~/output/20180603150000-777.aac outfile=~/猫_2018_06_06.mp4 output "$infile" "$outfile" infile=~/output/20180603010000-666.aac outfile=~/鳥_2018_06_06.mp4 output "$infile" "$outfile" output() { $infile=$1 $outfile=$2 if [ -e "$outfile" ]; then exit 0 else ffmpeg -i "$infile" "$outfile" fi } 一旦余計な変数を排除する output ~/output/20180603010000-888.aac ~/犬_2018_06_06.mp4 output ~/output/20180603150000-777.aac ~/猫_2018_06_06.mp4 output ~/output/20180603010000-666.aac ~/鳥_2018_06_06.mp4 output() { [ -e "$2" ] && exit 0 ffmpeg -i "$1" "$2" } >元のソースが汚いと修正も面倒だなとw だろ?w そこはスルーでええやん、別に求められているわけでもないんだし まあ、お疲れ様です(嫌味ではない) 日付の部分を元に戻す output "$(date +"%Y%m%d010000" -d last-sunday)-888.aac" "犬_$(date +"%Y_%m_%d" -d last-sunday).mp4" output "$(date +"%Y%m%d150000" -d last-saturday)-777.aac" "猫_$(date +"%Y_%m_%d" -d last-saturday).mp4" output "$(date +"%Y%m%d000000" -d last-friday)-666.aac" "鳥_$(date +"%Y_%m_%d" -d last-friday).mp4" output() { [ -e "$HOME/$2" ] && exit 0 ffmpeg -i "$HOME/output/$1" "$HOME/$2" } くだらん文字列結合を省く output "$(date +"%Y%m%d010000-888.aac" -d last-sunday)" "$(date +"犬_%Y_%m_%d.mp4" -d last-sunday)" output "$(date +"%Y%m%d150000-777.aac" -d last-saturday)" "$(date +"猫_%Y_%m_%d.mp4" -d last-saturday)" output "$(date +"%Y%m%d000000-666.aac" -d last-friday)" "$(date +"鳥_%Y_%m_%d.mp4" -d last-friday)" output() { [ -e "$HOME/$2" ] && exit 0 ffmpeg -i "$HOME/output/$1" "$HOME/$2" } 最終的にこんな感じかな(適当にやったので途中のコードはバグありだろう) output "%Y%m%d010000-888.aac" "犬_%Y_%m_%d.mp4" last-sunday output "%Y%m%d150000-777.aac" "猫_%Y_%m_%d.mp4" last-saturday output "%Y%m%d000000-666.aac" "鳥_%Y_%m_%d.mp4" last-friday output() { infile=$(date +"$1" -d "$3") outfile=$(date +"$2" -d "$3") [ -e "$HOME/$outfile" ] && exit 0 ffmpeg -i "$HOME/output/$infile" "$HOME/$outfile" } もっとやりたいならoutput関数を以下のような仕様の引数の関数ににしてもいいし output 010000 888 犬 last-sunday output 150000 777 猫 last-saturday output 000000 666 鳥 last-friday 順番変えてこうすりゃ最初の配列と同じようになる output 888 犬 010000 last-sunday output 777 猫 150000 last-saturday output 666 鳥 000000 last-friday まあ、配列なんかいらんっちゅー話だ >>230 > なんかだらだらって感じ だからいったろ? 元のコードが汚いと修正が面倒だって そうだな。やるつもりはなかったが、 例えば関数を作りたくなければ、こんな感じで行けるぞってことぐらいかな while read -r a b c d; do infile=$(適当に修正しろ) outfile=$(適当に修正しろ) [ -e "$HOME/$outfile" ] && exit 0 ffmpeg -i "$HOME/output/$infile" "$HOME/$outfile" done <<DATA 888 犬 010000 last-sunday 777 猫 150000 last-saturday 666 鳥 000000 last-friday DATA こういう場合は標準入力として受け取ってループで回せってことだな >>234 型なんて文字列しかねーよ HTMLのフォームからのPOSTと同じだ 白状する 181からここまで貼られてるソースコード全く読んでない 読む気起きない 別に構わんよ。きたねーコードだなって 直感的に思って、それを治すことで 俺の直感は正しいことを証明して 自分で納得してるだけだから 自分が汚いコード書いてた(誰でもそうだろう)&そこから綺麗にすることを学んだとこってとこかな もうちょっと経験つんだらそんな誰でもそうだったとこなんてスルーだろうな。綺麗にすることには際限がない/突き詰めれば&極論では個人の好みに帰結するってとこで、そんな初心者的なのにいちいち文句を言うのが低レベル的なw >>238 a=1 echo $((a + 1)) この場合の$aは数値じゃないんですか? >>212 for hoge in "$aaa" "$bbb" "$ccc" "$aaa" "$bbb" "$ccc"は、最初のアイテムを示すだけ(888, 777, 666)で間違い "${aaa[@]"が正しいもしくはとしたかったのだろうが、だったらforの機能的にも変数をArrayにする必要はないだろう。その記述以下でなんかするのでないなら aaa/bbb/cccは単なる文字列として、for内で必要となったらArrayに分解すれば簡単に目的は達成するだろう (てか、配列にするならaaa/bbb/cccなんて個々の変数じゃなくてそれこそそれを配列にすればいいのにと思うけど) aaa="888 犬 `date +"%Y%m%d"010000 -d last-sunday`" ... for fuga in "$aaa" "$bbb" "$ccc" do hoge=$($fuga) if [ -e ~/${hoge[1]}_${hoge[2]:0:4}_${hoge[2]:4:2}_${hoge[2]:6:2}.mp4 ]; then ... >>247 必要となったら数値とみなす/数値に変換するだけだろう a=hoge の場合は、hogeは数値に変換できないからしょうがないので0にしてまうし、 [ a -eq 0 ] なんて場合は、数値に変換できないのでエラーになるし。逆にa=1とかでエラーにならないのは数値だからと思えそうだが、単に数値に変換できてエラーにならないだけだろう あくまでも文字列でしかないのは、 a=1 a="1" a='1' のどれも同じってとこからもそう推察できそうな。そもそも明らかな文字列でさえa=hogeだったりするけど >>248 >"${aaa[@]"が正しいもしくは } 閉じ忘れ。てか、"${aaa[@]}"でも間違いで、"${aaa[*]}" だな >>248 >"${aaa[@]"が正しいもしくは } 閉じ忘れ。てか、"${aaa[@]}"でも間違いで、"${aaa[*]}" の方だった >>234 >>238>>249 以前にこちらのスレでお世話になった者で横からですが勉強になります >>248 ありがとうございます。 実は他の方のレスを見て、関数というものを調べて ある程度スッキリしたコードにできたのですが 当初自分の頭で考えていた>>212 のようなコードがが動くようにご指摘いただけたのは 非常に助かりました。ありがとうございます。 質問です。bashの配列を他のbashスクリプトに コマンドライン経由でわたすにはどうしたら良いのでしょうか? Arrayひとつを単一の文字列で渡して、受けたとった方がArrayに戻すかなあ sub-script.sh "${array1[*]}" "${array2[*]}" "${array3[*]}" ... sub-script.sh: array1=($1) array2=($2) array3=($3) Arrayのアイテムの内容がIFSに引っかかってたらIFSを書き換える(/同調)するかなあ。よくありそうなアイテムがスペースありとかだったら、アイテムの内容として入ってなさそうなタブにするとか (IFS=$'\t'; sub-script.sh "${array1[*]}" "${array2[*]}" "${array3[*]}" ...) sub-script.sh: array1=($1) array2=($2) array3=($3) (分解時のセパレータとしてはタブもデフォルトIFSに入っているので分解時には特に設定する必要はない) てか、そんなに配列をばんばん使わない方がいいんじゃねと思わなくもないw >>255 コマンドライン経由の意味はよくわからないが、 多分ファイルを使うのがいいと思う。 [渡す側] declare | grep "渡したい変数" > /path/save [受け取る側] source /path/save そのままでできると思う方が全くわかってないなという。まあ全くわかってないんだろうけど >>255 xmlなりjsonなり独自形式なりで渡せよ 言語のオブジェクト(配列)を他のプロセスにそのまんま渡せるスクリプト言語ってなんかあったっけ? 間にはシリアラズ/デシリアライズなどの仕組みがあるのは当然だが、そんなの全く意識させない言語でサポートしている言語って。フレームワークなど使えばは抜きで。スクリプト言語でなくてもいいけどとりあえずこのスレなのでスクリプト言語で >>257 あ、 >分解時のセパレータとしてはタブもデフォルトIFSに入っているので分解時には特に設定する必要はない 何言ってんだか。せっかくスペースをセパレータとされるのを避けているのに、設定しなきゃダメだろう sub-script.sh: ORIGINAL_IFS="$IFS" IFS=$'\t' array1=($1) array2=($2) array3=($3) IFS="$ORIGINAL_IFS" >>265 じぇーそんとかそういうためにあるんじゃないの? >>267 シリアライズ/デシリアライズの手法/フォーマットのひとつとしてね そゆんじゃなくて、そんな変換が見えなーい言語ってなんかあったっけ。仮にJSONを使っていたとしてもそんなの見えない 見えないってのがどういう意味なのか。 PowerShellみたいのなら見えないに入るのかな? 分散オブジェクトに近い...つうても実装/言語により全然見えないにはならんけど process.TheFunc(anObject) と、呼んだら、別プロセスの TheFunc(anObject) { } に、まんまオブジェクト(ただの配列でもいいけど)が入ってるくるような PowerShellはそんなんなん?分散オブジェクトかな? いや、>>259 なんて思うのはどういう根拠からかなあと。他のスクリプト言語でそんなんあるんかと また現れるかもしれんだろw まあ、スレチではある >>257 ,258,254 全部、シリアライズ/デシリアライズのことで、どういうシリアライズ/デシリアライズを使うかでしかなく、まあ、普通はそれしかないわなで終わってることなんだけどね ちょっとなんか他のスクリプト言語であるのかと気になったので 最近他板でも意味も分からず答える輩が増えていますね。何ででしょう。 新入社員が先輩よりプログラミング知識あることを知って俺結構世間の中でも出来る方なんじゃね?って勘違いする時期だな 解答のクオリティまで下がってるな パソコンの大先生混ざっとるやろ >>270 同一プロセス(要するにPowerShell内で閉じてる)ならそんな感じの記述でオブジェクトを渡せる ちなみにパイプでも渡せる 他のプロセスへコマンドラインとなると無理だろうね そもそもOSレベルでもたいていのOSはコマンドラインとして文字列の配列しか渡せないし POSIXで定義されているどの環境でも利用できる環境変数ってあります? $PWDとか。 >>280 環境変数で決まってるのは http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html ただしOS起動中まで含めると、必ず定義されてる環境変数はない。 PWDも昔のシェルだと定義してくれなかったりする。 まあ一般ユーザー権限で動いてるならPATH、HOMEあたりの存在は期待してもいいけど。 Excelから出力したCSVのように一行(?)の中に改行が含まれた データを扱うにはどうしたら良いでしょうか? もう少し具体的に書きます。 カンマ区切りのCSVデータだと仮定して、 シェルスクリプトの中に関数を一行ごとに呼び出し、 列を引数に対応させたいです。 例えば以下のような内容のファイルがあったとして a1,a2,a3,a4 b1,b2,b3,b4 c1,c2,c3,c4 syori "a1" "a2" "a3" "a4" syori "b1" "b2" "b3" "b4" syori "c1" "c2" "c3" "c4" という風にsyori関数を呼び出したいのです。 ただし実際には各項目(a1等の部分)にExcelから出力したデータのように 改行やカンマやダブルクォートやシングルクォートや空白が入ることがあるのです 各項目には \ が入ることもあります。 今回はCSVではありませんが、RFC4180(=ExcelのCSVの仕様)では 改行が\nのようにエスケープされません https://ja.wikipedia.org/wiki/Comma-Separated_Values > フィールドがコンマ、ダブルクォート、改行を含む場合は、かならずダブルクォートで囲む。 > また、フィールドに含まれるダブルクォートは2つ並べてエスケープする。 > > "日本 CRLF > 国","""東京""","127,767,944" CRLF ↑「日本国」の国の前に改行が入っている場合 >>283 rubyとかpythonでCSV処理用のライブラリを使うとか、 CSV処理用の専用ツール使うとか。 落とし穴が一杯あるので、シェルだけでやるのは危険。 >>285 危険は承知で環境依存させたくないので、 シェルスクリプト(POSIX)だけでやりたいのです >>287 じゃあ ttp://wwr2.ucom.ne.jp/tomoo/japana/csv.html とかどう? 邪道としては、改行コードとか\を絶対に使われない文字に置換して最後にまた戻すとかやったな アルメニア文字とかに置換するんやで 今時、シェルスクリプトが使える環境でperlやpythonがデフォルトで入ってないOSの方が稀だろう。なんかここ最近のPOSIXと言えばいいというようなのはなんかアレだな >>291 そういう環境で、CSVファイルの扱いが必要かあ? そんな変わりもんを出されても >>287 がそんなの想定してるとでも思ったの?そんなの想定しているヤツは自力でできるだろうし、そんなの使うやつは必要なら自分で入れるだろう 知識自慢はいらんよw てゆうか問題に適した言語を組み合わせて問題を解くってのが もともとのUNIXの思想だと思うので、 CSV扱うならCSVに向いた言語使う方がUNIX的だと思うのよね。 まあケースバイケースなんだけど。 https://codezine.jp/article/detail/8323 >gawkの開発は「完全を目指すのではなく9割をサクサクこなし、フィールドに改行を含むようなCSVファイルは専用のツールで処理すれば良い」 ですらだからなあ Linuxはawk=gawkだが、BSDは巣の(?)awkでgawkは別に入れなければならなく、gawkの機能を使うかどうかっていう話ならわかるけど、そんなんだったらperlやpython使った方がLinuxとBSDの違いも無いだろしな >>287 は単に他の言語/知識までは自分の手に余るっていう逃げだろうとしか見えんな そこに山があるから登るっていうあえてメンドくさいことをしたいってのなら、のらないでもないけどw とは言ってるけど、CSVとはどう違うとかは全くだな。てか、延々とCSVのここがってしかないやん CSVと似た何か特殊なものなら、普通にストリームの一文字一文字処理できるスクリプト使ったほうがいいだろう、てかそれしかないだろう ■ このスレッドは過去ログ倉庫に格納されています
read.cgi ver 07.5.1 2024/04/28 Walang Kapalit ★ | Donguri System Team 5ちゃんねる