シェルスクリプト総合 その29
■ このスレッドは過去ログ倉庫に格納されています
!extend:on:vvvvv:1000:512 !extend:on:vvvvv:1000:512 シェルスクリプトに関する総合スレッドです。 スレ立て時は以下の文を先頭行に加えて下さい。 後のつけ忘れ防止の為に複数行重ねて追加推奨 !extend:on:vvvvv:1000:512 全般 ・荒しは無視しましょう。 ・丁寧な姿勢を心掛けましょう。 ・ネチケット(死語)を意識しましょう。 前スレ シェルスクリプト総合 その28 http://mevius.5ch.net/test/read.cgi/tech/1532397676/ VIPQ2_EXTDAT: default:vvvvv:1000:512:----: EXT was configured ああ,なんか説明不足で投稿しちゃった。 つまりさ,一応標準で定められたエラー番号はあるものの, 各種アプリケーションが従っている訳でもなく Debian系のaptコマンドのような超大手のアプリケーションでさえ標準を無視してるんだから, > 定義済みを除けば残りは79〜113かな ↑こういうのは考えないほうがいいんじゃない? ってこと。 >>105-106 どこかのなにかにかぶってしまうのは防ぎようがないけど よく使われるコマンドがこんな終了コードを使っていたっていう事例を知りたいのよ fsckとかどう見てもエラーじゃねーだろコレっていうのが エラーあつかいになってて以前はハマったことあるしw https://linuxjm.osdn.jp/html/e2fsprogs/man8/fsck.8.html > 1 - ファイルシステムのエラーが修正された 標準に準拠したいとかそういう話ではなく 単にぶつかりたくないだけ > exit 100を返すというトンデモ仕様[Debian 2015]なので,もうどうしようもないんじゃねw 実を言うと今100を使おうとしていたw やはり裏の裏の裏の裏ぐらいを読まないとダメだなw シグナルでも使ってみたらどうだろうか。 あるいは別にパイプを用意するとか。 絶対にぶつからないようにするには別の方法でエラーを伝えるようにするぐらいしか方法ないんじゃないか? 同じ値になる可能性のあるものをどちらから発生したかわからない状態で同じ所から得るなんてやはり無理があるだろう。 こんな書き方できたのか a=1 case $a in ( 1 ) echo ok esac お題 ある関数に対して、apple orange banana ... とN個(Nは任意の個数)の引数を渡した時、 以下のような、引数とその引数のインデックス番号を出力する関数を作成せよ (単語に対して数値が対応しているわけではない) apple 1 orange 2 banana 3 : ただし、外部コマンド、拡張POSIX機能、変数の使用は禁止とする (ここでいう変数とはsetコマンドで表示されるもののことである) >>115 argidx() { i=1 for argv in "$@"; do echo "${argv}" $i i=$((i+1)) done } 簡単すぎ おいこら答えてやったんだからなんとか言えよコラ エレガントすぎて腰が抜けたか?wwwww まあ実際,自分で言うのもなんだけどかなり最良に近い方法じゃないかしら。 ・POSIX.1-2017準拠 ・空白などを含む引数も直感的に指定可能("word with space") ・単純 構造が簡単 ・数値の増加にexpr(1)ではなく算術式を利用している為速い >>115 といい、>>117 といい変なヤツしかいないやんけ 最初の一個だけならスマートだったのに 褒められたがりが 煽りだよ だって明らかに学校の課題かなにかでしょ。 そんなのに真面目に付き合うほど俺は素直じゃない。 >>115 echo は使っては駄目? 拡張されていない sh だと echo はビルトインではなく /usr/bin/echo だと思うが。 >>118 そう。変数禁止なので不正解 >>121 変数禁止とか学校の課題ででるわけないじゃないw >>124 使ってOK。 俺の知る限りechoがビルトインでないものは知らない 関係ないけどechoみたいな基本的なコマンドが シェルによって挙動が違うのはどうにか ならなかったんだろうか そうか。evalとか外部コマンドは実装不可能なものを除いて ビルトインで実装することなんて決まりはないのか では外部コマンドの定義を「現存するシェルでビルトインで実装されたことがないもの」にしよう オレオレシェル作ってビルトインするのは問題の意図から外れるので、 現存する(誰もが容易に入手可能な)いずれかのシェルで ビルトインされているならば使って良いものとする あと拡張POSIX機能も使用してOKにしよう。 それを実現する裏技みたいなのがあったら嫌だなと思って入れたが、 もしそれでできるなら俺も勉強になるし。 ようするにPATH環境変数を空にして、どれかのシェルで動けばOKってことだな 条件がグダグダになってしまったw if や while を外部コマンド動かさずに使うには [ がビルトインのシェルでないとダメだな。 昔の sh は [ が test コマンドへのシンボリックリンクで外部コマンドだったし。 今でもその名残で /bin または /usr/bin に [ が入ってるよな。 別件で現在主要のシェルで何がビルトインか調べたことがあるよ . : [ break cd command continue echo eval exec exit export false kill pwd read readonly return set shift test times trap true umask unset wait これらは全てのシェルで使えると言っていいだろう poshはログインシェルとしては使わないもの扱いなのか alias bg fg type ulimitが削除されている。(typeないとか地味につらい) busyboxはgetoptsがないみたい 意外だったのはprintfがビルトインでないシェルがmkshとposhの2つもあったこと。 しかも両方共echoでエスケープシーケンスを解釈してくれるから文字をそのまま出力できない。 mkshの方はset -o posixでエスケープシーケンスを無効にできるしビルトインのprintで代用できるんだが poshは調べた限りビルトインコマンドでそのまま出力する方法がない いいから、お題の参考答えを出しなさいw オレオレ定義が曖昧すぎでお題になってないから、もういいでしょ >>131 問題訂正してやるから、もう少し頑張れやw お題 ある関数に対して、apple orange banana ... とN個(Nは任意の個数)の引数を渡した時、 以下のような、引数とその引数のインデックス番号を出力する関数を作成せよ (単語に対して数値が対応しているわけではない) apple 1 orange 2 banana 3 : ただし、変数の使用は禁止とし、シェル機能とビルトインコマンドのみを用いること (ここでいう変数とはsetコマンドで表示されるもののことである) (使用するコマンドはいずれかのシェルのビルトインコマンドであればよいが、 この問題用に独自シェルを作成するのは禁止とする) なんの目的かさっぱりわからんな。自分でできてんの?っていう疑問からなんだけどなw >変数の使用は禁止とし >(ここでいう変数とはsetコマンドで表示されるもののことである) 環境変数のことを言っているのかと思えば違うし、これだけでも曖昧というかオレオレ定義が曖昧だろう >>133 setコマンド実行してみてみばわかるでしょw setコマンドで表示される変数はシェル変数(環境変数含む)だよ それを使うのは禁止ってこと 今日の24時までに答えが出なければヒント出しますw 変数を使わない 言語(マシン語すら) は知らんなあ。そういう縛りを設けての目的はなんなん? やってみたできるけど、クソのようなwにしかならんから、どうか、参考の答えを出してw 答えは明日。まあヒントみれば気づく人はすぐわかるでしょう。 コロンブスの卵だよ なんで常時上から目線なのかw コードで語ればいいのに 素晴らしいコードならそんなおれおれ上から目線しなくてもいいくらいなのに。なんかしらんがもったいつけてのまだ「ヒント」とかもったいつけてるしw なんかしらんが見つけて、俺すげーしたいだけっぽいなw > そういう縛りを設けての目的はなんなん? その理由も答えと一緒に明かします いや、もういらんわw なんかキモすぎて付き合いきれないw 多分だけど学校の課題だと予想 根拠は二点: 1. 問題が実利的でない。学校(それもあまり学力の高くない)にありがちな「こんなのできるかな?」系の問題である。 2. 煽ったらそれに乗っかって答えを出してくれる人が思ってるという点で質問者が精神的に幼ない。(高校生くらいか?) posh とかいつもの人でしょ いつもの人が学校の課題をしなきゃならん人なのか知らんけどw >>2 に書いてあるよ。俺もここ(の何スレか前)で初めて知った $# と shift を使って逆順に値を付加することは簡単にできたんだがな。 >>147 俺も第一歩目はそこまでだったw 俺の本来の目的(今回の問題とは別件)は逆順でも実現できたんだけど なんか悔しかったので、もう一歩進めたら逆にすることなく実現できた 変数使ってはダメって、非合理的でない? シェルの仕様否定してどーするの? 外部コマンドだって、それがUNIXの設計思想なんだからそれさえも否定するってのも理解不能 ならば、OSそのものを仮想的なものを仮定して その上で動かすとでもしないと 大昔の情報処理技術者試験用に作られたアセンブラみたいな感じでさ 変数使わない、外部コマンド使用禁止、そんなアルゴリズムが何の役に立つんだろう? でも前はワッチョイやIDがなかったから もっと酷かった。 今はNGすればオッケー☆ ヒント忘れてたわw func() { ********* while [ $# -gt 1 ]; do ********* shift done } func apple orange banana ********の所は1行とは限りません >>150 シェルスクリプトはPOSIXの範囲では ローカル変数がないから、変数名がかぶると困るんだよ もちろんサブシェルを使うという手もあるが 引き出しは多いほうが良い >>151 それなw 見たくないやつが絡んでこなくなったので 過ごしやすくなった。 >>150 ちなみにこれアルゴリズムじゃないよ アルゴリズム系だと一時変数を使わずに変数を入れ替える方法とかあるけど これはシェルの機能を使った、あぁ、なるほど系の問題 >>152 よ、お前のなかでは「$#」は変数じゃないのか……。 人様にクイズとやらを出す前にシェルとはなんなのかを学んだらどうだ? 出題ぐらいちゃんと読もうぜw > ただし、変数の使用は禁止とし、シェル機能とビルトインコマンドのみを用いること > (ここでいう変数とはsetコマンドで表示されるもののことである) bash 4.2以降はset組み込みコマンドの中に$#が含まれるようになったんだよなぁ… ちゃんと調べて、どうぞ。 ないですね。ちゃんと調べてどうぞ foo() { set | grep '#='; }; foo $ bash --version GNU bash, バージョン 4.4.19(1)-release (x86_64-pc-linux-gnu) Copyright (C) 2016 Free Software Foundation, Inc. ライセンス GPLv3+: GNU GPL バージョン 3 またはそれ以降 <http://gnu.org/licenses/gpl.html> ; This is free software; you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. >>160 grap のパターンはそれでいいのか? >>161 良いに決まってるだろ 正規表現に自信がないなら自分で調べたら? 質問してるってことは、動かしてないんだろうし。 ああ。そうか。最初の$は要らないからそれでいいのか。 なんかもう誰かが作ってそうだよね。 まるでyaから始まる4文字のソフトウェアが被りまくってるように。 正解者もいないようなのででは解答 このコードがどういうときに有用かは>>153 で書いたとおり set は使わなくても別にもう一つ関数を作れば同じことができるが 関数を作らずとも引数の再設定という方法がある。意外と便利だよ func() { set -- "$@" $(($#+2)) while [ $# -gt 1 ]; do eval "echo \"$1 \$((\$$#-$#))\"" shift done } func apple orange banana そんなクソなコードを意気揚々としてあげてるけどさ、なんか変数被るからというもっともらしい言い訳してたけど、なるべく変数使わないように書くわけだ、これから。ほーっw。そんなのクソだな、個人的にw なんでそういうお題をそんな俺偉いじゃなくてできないのかな。よほどそれを出すのに時間かかったとか?? いや、ふつうわかるだろう。まあ、かなり頑張って出したんだね、やっぱりw だから、なんでそんな上から目線なのよ んなのに付き合うと思ってるの?あんた自体が上から目線でモノ言われたらすぐ反発するくせにww >>172 お前はこのおっさんと同じ種類の人間だろうな 相手が下だと思って接してるやつ。 まずお前が上から目線を止めたら? https://togetter.com/li/1175445 おっさんがタメ語で聞いてきたからタメ語で返したらショックを受けてた。敬意が返ってくると思ってる日本のおっさんって不思議。 いや、お前に合わせているだけだな。さすが常時上から目線なんかしらんが常時上に立ちたいの人は言うことが違うなw 上にたってるつもりはないんですが、上に見えちゃうんですかね?w 悪い奴らが「正義の味方のつもりかよwww」って 笑ってるようなシーンがあるけど、あれも悪い奴らに 正義に見えてるからそう言うんでしょうねぇ 忘れているのか常時上に立っているつもりで気がつけないwのか知らんが、ID:8ua9ZMtc0 の上から目線なレスに対しての俺のレスでしかないよ なので、その得意げの>>174 はそっくりそのままあんたにお返しいたします あーあ、病気なのか社会性がないのか話にならんな。まあ、いつもの無理やりなごまかしモードかな?w これはある意味有名だから簡単だと思う お題 ある関数に対して1以上の整数Nを引数にして呼び出した時、 1からNまでを出力する関数を作成せよ(要するにseqコマンドの簡易版) seq 5 1 2 3 4 5 : ただし、シェルビルトイン関数のみを使い、変数の使用は禁止とする (ここでいう変数とはsetコマンドで表示されるもののことである) >>167 それ最初のposix縛りがあったら解けなくないか? $(( ))で計算させてるし。 レス番飛び過ぎにも程があるだろ まぁいつもの長文だらだら流して悦に浸ってるんだろうが >>181 これは興味から訊くんだけど, 「(POSIXの範囲では)変数の局所化ができないので 変数をなるべく使わないべき」 という主張は理解できるし,俺自身もそう思う。 しかしシェルビルトイン関数しか使わず,例えば sed(1)やawk(1)など目的に合った有用なコマンドを用いない理由はなんだ? ただの趣味? >>181 $(( )) での計算をしていいなら簡単だよ。 #!/bin/bash f() { if [[ $1 -gt 0 ]]; then f $(( $1 - 1 )) echo $1 fi } f $1 >>187 現実的なポータビリティと速度のため POSIXの範囲でやれば、シェルが異なっても動くことが期待できる だけど現実的にはすべての環境がPOSIXに準拠してるわけではない 特にbusyboxは組み込み向けに必要最小限の機能に減らせるから sedやawkすらない環境というのもあり得るだろう そしてもう一つforkは遅い。WSL上だと目に見えて遅い 以下のコードをWSLで実行すると約25秒かかる。fork一回あたり2.5ミリ秒 Linuxだと約2秒。fork1回あたり2ミリ秒。10倍以上の差がある i=0 while [ $i -lt 10000 ]; do ( :; ) i=$((i+1)) done この()を外すとWSL上で0.05秒にまで減る。コマンド実行のオーバーヘッドに 埋もれてしまってよくわからないので、10,000から1,000,000から増やすと約1.7秒 つまり一回あたり0.0017ミリ秒。この値はLinuxでも変わらない 外部コマンドの実行でもforkが行われるから Linux・・・0.0017ミリ秒 → 2ミリ秒 (約1176倍) WSL・・・0.0017ミリ秒 → 25ミリ秒 (約14706倍) と大幅に速度が落ちる。シェルスクリプトが遅いと言われる原因の一つ なんもわかってない低学歴知恵遅れが はりきってしょうもないwsl使ってキャッキャッいってるわけか なるほどなるほど wsl使ってるのなんかニートぐらいしかいないわ マジで >>188 やっぱり簡単だったかw 再帰を使うやり方で関数型言語ではおなじみの問題 もちろんシェルスクリプトは関数型ではないし 末尾最適化も行われないのでどうしても遅くなる さすがにこれは変数使ったほうが良いかな思ったw 他にも問題を作れそうなネタのはいくつかあるんで 気が向いたらまた問題にしてみるよ >>191 やっぱ内容には全く触れず 叩けそうな所を叩くだけなんだなw 技術者としてつまらないね 実用的じゃないもの書いてるうちは似非の技術者じゃの >>190 シェルスクリプトはストリーミング指向だから そもそも制御文を多用することは避けたほうがいいのではってのは違うのかな。 >>195 ストリーミング指向と制御文はあまり関係ないと思うよ 流れてくるものに対してなにか処理をしたいなら必ず 制御文を使うことになるし ストリーミング指向の話をするなら、関数呼び出しし結果の標準出力を 変数にキャプチャするっていうのはストリーミング指向と反してると思う 例えば result=$(command "$data") みたいな形のことね 俺もこの書き方はなるべく避けるようになった ストリーミング指向的には echo "$data" | command | 別のなにか とするほうが良いだろう ただ気づいたのがこの形だとサブシェルになってしまうから、 commandや別のなにかから、呼び出しの起点にデータを戻すことが 簡単にはできないという所。値を戻すこと自体がストリーミングの流れに反しているし かと言ってそれが必要な場合もある。例えば処理した行数をカウントしたりとかね。 なので最近はイベントハンドラ方式を使うようになった echo "$data" | command "別のなにか(関数名)" (または command "$data" "別のなにか") 例えばだけどこんな感じにして、commandで$dataを1行ずつ処理して その都度、別のなにか(関数)を呼び出す。そうするとサブシェルにはならないので ストリーミングで処理しつつ、グローバル変数経由で呼び出し元に結果を返すことができる この時、別の何かがシェル関数の場合に、commandが外部コマンドだとシェル関数を呼び出せないので 連鎖的にcommandもシェル関数として実装。みたいなこともやってたりする 10. 移植性のあるシェルプログラミング http://web.sfc.wide.ad.jp/ ~sagawa/gnujdoc/autoconf-2.59/autoconf-ja_10.html >>196 なるほど。 俺は https://www.ipsj.or.jp/dp/contents/publication/32/S0804-R1601.html ここの3.1.1を読んで、制御文をなるべく使わない方向に開発をシフトしてみたんだよね。 まあどうしても必要な部分はあなたも云ってる通りもちろんあるけど。 >>198 別にその記事に大きく反対したいわけじゃないけど おかしな点は指摘しておかないといけない その手続き型コーディングがステップ数が多く処理効率が低いと書いてある所だが その原因はストリーミング型コーディングのせいじゃない rmコマンドの発行回数が原因だ ■手続き型コーディング(ステップ数が多く処理効率が低い) i=3 while [ $i -le 10000 ]; do file="file${i}.txt" rm -f "$file" # 何度もrmコマンドを実行している i=$((i+3)) done 結果 real 0m3.232s user 0m2.488s sys 0m0.808s ■ストリーミング型コーディング awk 'BEGIN{for(i=3;i<=10000;i+=3){print i;}}' | sed 's/.*/file&.txt/' | xargs rm -f 結果 real 0m0.040s user 0m0.004s sys 0m0.040s プロセスが分かれており並列で動く可能性があるから 多少ストリーミング型の方が早くはなるとは思うが 以下のように修正すると差は殆ど無くなる。 ■手続き型コーディング修正版 i=3 files() { while [ $i -le 10000 ]; do file="file${i}.txt" echo $file i=$((i+3)) done } rm -f $(files) 結果 real 0m0.052s user 0m0.018s sys 0m0.044s 余談だがこれはLinuxで実行した結果だがforkが遅いWSLだと 起動プロセスが多い分逆転するかもしれない 訂正 その手続き型コーディングがステップ数が多く処理効率が低いと書いてある所だが その原因は手続き型コーディングのせいじゃない >>200 非本質的だけど rm -f $(files)とかだとARG_MAXに引っ掛かる可能性がない? 尤も手元の機械では $ getconf ARG_MAX 2097152 だったので無問題かも知れないけど。 >>202 > rm -f $(files)とかだとARG_MAXに引っ掛かる可能性がない? あるよ。それならxargsを使えばいいし、 xargsはファイルから読み込む方法もあるからパイプ使わなくても使える。 ともかく速さの理由はストリーミング型コーディングではないと言いたかっただけ だいたいawkの中に書いてあるコードは手続き型だろといいたいし、 ステップ数だってちょっと書き方変えれば、大差ないってのがわかるだろう i=3; while [ $i -le 10000 ]; do rm -f "file${i}.txt" i=$((i+3)); done awk 'BEGIN{for(i=3;i<=10000;i+=3){print i;}}' | sed 's/.*/file&.txt/' | xargs rm -f お題 関数fooに対して3つ以上の引数を渡した時、1番目と2番目の引数を入れ替え以下の例のように出力せよ (引数が3つ未満の場合は考慮する必要はなし) ただし、シェルビルトイン関数のみを使い、変数の使用は禁止とする (ここでいう変数とはsetコマンドで表示されるもののことである) foo 1 2 3 4 5 2 1 3 4 5 レベル1: 引数に使用する文字は英数のみとする レベル2: 引数にダブルクォート、シングルクォート、スペース、タブが含まれていても動作するようにせよ あ、いかん。>>204 は簡単な解答があるわw ちょっと修正する お題(>>204 の訂正版) 次のような関数barがある。 bar() { echo 'begin'; printf '%s\n' "$@"; echo 'end'; } 3つ以上の引数を渡した時、1番目と2番目の引数を入れ替えて関数barを呼び出す関数fooを作成し 以下の例のような出力をせよ(引数が3つ未満の場合は考慮する必要はなし) ただし、シェルビルトイン関数のみを使い、変数の使用は禁止とする (ここでいう変数とはsetコマンドで表示されるもののことである) foo 1 2 3 4 5 [出力] begin 2 1 3 4 5 end レベル1: 引数に使用する文字は英数のみとする レベル2: 引数にダブルクォート、シングルクォート、スペース、タブが含まれていても動作するようにせよ ■ このスレッドは過去ログ倉庫に格納されています
read.cgi ver 07.5.5 2024/06/08 Walang Kapalit ★ | Donguri System Team 5ちゃんねる