シェルスクリプト総合 その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 >>562 個人的な特殊な状況下で気をつけてることならたくさんあるんだけどな パイプを(なるべく)使わないとかwww そうさなぁ、例えば意図せぬエラーで落ちるように、set -eを使う場合は 挙動をよく理解して使うこととかかな set -eは戻り値がエラーになった時点で中断される set -e foo() { echo foo begin; bar; echo foo end; } bar() { echo bar begin; baz; echo bar end; } baz() { echo baz; false; } foo これを実行すると、foo -> bar -> baz の呼び出しの流れが、bazのfalseで中断されて foo begin bar begin baz と表示されるんだが foo の代わりに if foo; then :; fi と実行すると なんと、foo end も bar end も表示されるんだよ つまり foo を if や && や || と組み合わせて使うと、エラー中断機能が無効化される だから、比較関数みたいに if foo; then という使い方を想定している関数は 中でしっかりエラーチェックをしておくこと 他の言語の例外みたいに考えてはいけない ↑ これが理由で、set -eは使うな派もいるらしいねw >>562 > 例えば「局所変数や局所関数が宣言できないのでなるべく使わない」とかさ。 俺は訳あってそうしてるけど、特定のシェルに限って良いのなら localもしくはtypesetで局所変数使えるよ ただし、他の言語と違ってレキシカルスコープじゃなくて ダイナミックスコープなので注意が必要 これも気をつけていることかな あと他の言語でも同じだけどshellcheckは基本やね ダブルクォートでくくるとか、shellcheckで警告出るものは ここでグダグダ書かないよ。 >>563 パイプが詰まってんだから停止させるしか方法ないと思うが? バッファ大きくしても出力側が速いなら何れ突っ掛かる事になるよね。 >>568 そりゃそうだよねって話ではあるんだけどさ、 パイプで何かに繋いだがために処理が遅くなることもあるよなって思ってね 明らかにそんなレベルの回答求めてないよねっていう語りたがり ん? あぁ、質問はコレね > メモリにバッファリングするだろうから、それが溢れないような処置として > そういう仕様は理解できるけど、どこかに書いてあるのかな? > > シェルの仕様っぽい気がするけど、OSも絡んでいそうな気もする >>565 ありがとう。set -eは鬼門だね。前に棘かなにかでも纏められてた。 ところで パイプ使わないのはどうしてだ? シェルスクリプトは入出力指向なんだから積極的にパイプを活用すべきでは。 >>573 パイプ使わないのはシェルスクリプト内部で完結する場合の話ね 外部コマンドとのインターフェースでは使う (内部で)使わない理由は変数の共有がやりづらいから ま、これは特殊な事例なのでw ああ。たしかにパイプ越しに変数を参照させようと思ったらexportして環境変数にしなくちゃらんもんな。 > ああ。たしかにパイプ越しに変数を参照させようと思ったらexportして環境変数にしなくちゃらんもんな。 もうちょっと説明すると foo() { output | bar | baz } fooで見えてる変数を、bar, bazに見せるのは簡単なんだよ。 exportしなくても見せられる。 outputが出力する1行をbarが解析して変数に入れたとして、その変数を bazで見ることはできない(barでexportしても無理) bazが複数行の入力を集計した結果の変数をfooで見ることが出来ない。とかね 1データを1行に詰め込めればパイプ経由でのデータ受け渡しは可能だが それができないデータだと難しい 他の言語でやれって? それをシェルスクリプトでやらなきゃいけないというのが個人的な特殊な状況下というわけ シェルスクリプトでそのコマンドが実行された行数を取得する方法ってあるかな。 #!/usr/bin/env bashにすれば${LINENO}変数にその位置が格納されてるので簡単なんだけど やっぱりもうすこし汎用的な方法で実現したい。 >>577 LINENOしかないよ。ただしご存知の通りLINENOは使えないシェルがある。 dashなんか機能的には搭載されてるがdebianなどでは無効にされてるというw 更にシェルによっては関数呼び出しを行った時にソースコードの行数ではなく 関数の頭からの行数になっていて、それも0から始まるものと1から始まるものがある まともに使えるのはbashだけかな >>578 だよね〜。ファイルの中での自分の位置を調べるのはシェルスクリプトでは無理っぽいね。 Cのassert()関数みたいなのを自作したかったんだけど 機能が落ちるのは嫌だな(もういいけど) ああ ちなみに > 関数呼び出しを行った時にソースコードの行数ではなく > 関数の頭からの行数になっていて これGNU Bashのことを言ってるのなら関数じゃなくて別名にすればO.K.だよ >>579 シェルスクリプトの世界にJavaScriptのトランスパイラ技術が導入されて ソースコードの一行一行にLINENOを設定するコードを埋め込めば 解決できると思うんだが、流石にそれをやろうとする人はいないかなw > これGNU Bashのことを言ってるのなら関数じゃなくて別名にすればO.K.だよ alias?うーん、なんか別の問題がでそう。 でもbashじゃなかったと思う。 前に調べたときのコードを見てみたが、 関数の頭からの行数になるのはzsh, dash, busybox ashで zshは0から始まる。他は1から始まる。bashとkshはソースコードの行数で取れる。 バージョンは詳しく調べてないから多分古いやつは使えなかったりすると思う なので他のシェルでエラーが起きたら、bashで実行してエラーの行番号を調べたりしているw たとえばシェルアーカイブってPOSIXシェルでも可能だよね。 ああいう感じで自分が含まれるファイルを自分で走査できるんなら 行位置も取得できないかなぁと思ったんだよね……。 しつこいけどシェルスクリプト版のassert()関数が欲しい っていうか作りたいんだよねぇ >>581 assertだけなら簡単かもしれないな。 assert関数の中で全てを処理するのは難しいと思う。自分のスクリプト名でさえ取得できない場合があるから 仮に取得できたとしても、何かしらのマーカーがないとどのassertかが区別できない。 (全ててのassertに区別できるマーカーを入れるっていうのなら可能だけどw) 前提としてLINENOが取得できないのはどうしようもないのでコード変換を行なう foo() { asesrt [ i -gt 0 ] } みたいなコードがあったら以下みたいに、行番号を埋め込むプログラムを作る (ファイル名もあったほうが良いかもしれない) foo() { asesrt 2 [ i -gt 0 ] } これはPOSIXシェルスクリプトの範囲でもできる。一行づつ読んでパターンにマッチしたら変換するだけ (複数行文字列やヒアドキュメントがあったら面倒だけど、対応してませんでもいいと思う) あとは以上の変換処理を行って実行するラッパースクリプトを作って実行する 変換したコードはevalもしくはシェルにパイプで流し込むことで実行できる。 あー、そうか、assertか、ならデバッグ時のみしか有効じゃなくていいな。 なら、普通にスクリプトを実行したときは、 何もしないassert関数になって、 debug.sh script.sh みたいにしたら、 コード変換を行ってから実行すれば良いのか 意外と自然な感じで作れそうw assert失敗時に強制的に停止させるのはkill $$で行けるかな? サブシェル内でも一応停止できるようだけど 色々考えてくれてマジでありがたい 確かにassert()関数はデバッグの時だけ有効になればいいから外部からスクリプトファイルを操作するという方法も なんら不自然ではないな。 C言語のようにNDEBUG変数の有無によって処理を分けようとしてたけど そっちのほうが柔軟な処理ができるのでいいね。 ていうかC言語と違ってシェルスクリプトのなかで安全・確実に変数を取り扱うのは厄介だから 寧ろNDEBUG変数は害悪ですらあるなw >>585 何もしないassert関数と書いたが、コメントの形でassertを入れるのはどうだろう? これなら関数呼び出しすらないので、(わずかな)パフォーマンス低下も発生しないし 仮にスクリプト内でassert関数を使っていても問題ない assert有効時は、長い名前に変換すれば良い あと、デバッグモード、assert関数有効時だけど、終了ステータスを変えてしまうことに注意な foo() { false # assert [ なんちゃら ] echo $? } という場合、本来はechoで1と表示されるけど、単純にこのように変換してしまうと、 assert有効時に$?がassertの結果になってしまう だから変換後はこんな感じかな? ||:を使うことでset -e状態でも落ちなくできる foo() { false assertooooo 3 [ なんちゃら ] ||: echo $? } assertooooo() { EXIT_STATUS_BACKUP=$? LINE_NUMBER=$1 shift if "$@"; then return $EXIT_STATUS_BACKUP else echo "エラー $LINE_NUMBER" >&2 exit 1 fi } > 仮にスクリプト内でassert関数を使っていても問題ない ちょっとわかりづらかったな スクリプトでassertという名前の関数を別の用途で使っていた場合ってことね うぬ、ここはkillにするんだった else echo "エラー $LINE_NUMBER" >&2 kill $$ fi (ま、あとは . ドットコマンド で読み込んだ外部スクリプトはどうするか問題があるんだがなw) あー、バカだ assertooooo 3 [ なんちゃら ] ||: じゃなくて assertooooo 3 [ なんちゃら ] &&: だった 上はset -eでも落ちなくし、かつ終了ステータスを問答無用で0にする方法(エラーの時 : を実行する) 下がset -eでも落ちなくし、かつ終了ステータスはそのまま保つ方法 >>590 例えば ファイルの名前がwhizprog.shだったとして test "$( ps -p $$ -o 'comm=')" = 'whizprog.sh' ↑これが失敗・失敗しないで判定できるんじゃね? 尤もこれはシバン#!/bin/shというPOSIX未定義の構文を使ったばあいで シバンを書いてないと使えない手だけど。 >>592 ん? assert実行するためのソースコード書き換えの話だよ debug.sh script.sh で読み込んだ、script.shの書き換えは簡単だけど、 その script.sh から . コマンドで読み込まれるコードまでは書き換えられない だから . コマンドを検出して再帰的に・・・面倒なんだよなw 余談だが、 > test "$( ps -p $$ -o 'comm=')" = 'whizprog.sh' これはPOSIX準拠なのだろうが、busyboxではpsはwしか使えないw ps w >>593 ああなるほど そんなことまでは考えてなかった。 正直,あなたに教えてもらった方法で大満足です。ありがとう。(欲を言えば行番号を自分で……しつこいねw) とりあえずこんな感じに落ち着きました↓ #!/bin/sh assert() { exec >&2 eval "test ${2}" || { printf '%s: %d: %s\n' "${0}" ${1} "${3-"Assertion ${2} failed."}" exit 1 } } main() { set -eu umask 0022 export PATH="$( command -p getconf PATH ):${PATH}" assert 18 '"a" = "b"' && : exit $? } main "$@" update.sh script.sh でassert行の行番号を更新して上書き保存するってのもありかもw それなら.コマンドの先も対応できる。いちいち更新しないといけないのが面倒だけど 更新するコマンドを別に作るんじゃなくてデバッグ時に更新も行うようにすれば(結局 手間は同じだけど) だってデバッグする時ってその直前に必ず行番号やらを更新したいでしょう。 だんだんそもそもやりたかったことから離れてる雰囲気だけは感じた >>596 まあ、そうなるよねw まあ、方針次第だな >>597 ようするに、シェルスクリプトの世界にもトランスパイラが欲しいって話さ ちなみにどれだったか忘れたがシェルスクリプトの文法を 解析するやつ(ASTを作る)はすでにある それを使えばそんなに難しくはないと思う(とは言えやったことはない) もうシェル自体に手を入れてデバッグモードみたいなのを実装した方がいいんじゃね? >>599 一応POSIXでsh -xは定められてる sh -xまじ使えねぇ なぜ行番号を出すようにしなかったのか >>603 ほ ん と そ れ そして今調べて気が付いたがsh -xじゃねーなw set -xだわ。 > The -a, -b, -C, -e, -f, -m, -n, -o option, -u, -v, and -x options > are described as part of the set utility in Special Built-In Utilities. > The option letters derived from the set special built-in > shall also be accepted with a leading <plus-sign> ( '+' ) instead of a leading <hyphen-minus> > (meaning the reverse case of the option as described in this volume of POSIX.1-2017). http://pubs.opengroup.org/onlinepubs/9699919799/utilities/sh.html#tag_20_117_04 >>604 なんでワイに聞くねんwバカなんかおまえ? C言語ではなくシェルスクリプトでシグナルって活用してる? kill(1)ユーティリティの-s KILLオプションくらいしか使ったことがないので いまいち便利さが分からない。 利用者定義シグナルSIGUSER1とか 使いこなせたらシェルスクリプトでできることの幅が広がりそう CTRL-Cされたときとかプログラム終了時に 作業ファイルを削除することぐらいかなぁ あとはシグナルじゃないけど、bashの疑似シグナル ERRとかDEBUGとかで遊んだことある サービスなんかだとシグナル送ったら設定ファイル再読込したり ddだったら進捗状況表示したりするね >>612 終了処理をちゃんとやらないといけないような処理の場合に trap 使ってシグナルに対して 特定の変数を 1 にするだけとか、そういうやり方で終了処理後にその変数見て 1 になって いたら exit みたいな感じでシグナル利用するな。 後は普通に kill で他のプロセス終了させたい場合。pkill 使う事もある。 実行してるシェルスクリプトに行番号を付けるのさ, PS4変数にn=$((n+1))みたいなのを入れてset -xとやればうまくいくかな と思ったんだが無理っぽいな。 どっかで無限ループして何も出力されないw 算術式のなかにコマンド展開を突っ込むのってPOSIX違反かしら echo $(($(< ./file.txt wc -l)-1))←こういうの。 >>617 なるほど。今手元にあるGNU/Linuxでは普通に動くけど やめたほうがいいかもね。 Solaris 10とかで失敗しそう(使うことないだろうがw えぇ・・・ 俺普通にこんなの使ってんだけど? value=$(( ${value:-0} + 1 )) 普通に展開されるんじゃないの? >>619 まあ俺も使い捨てのスクリプトでは使うけど ただPOSIX 2017では x=3; x=$((x+1)) ↑これすら正常に動くとは定義されてないんだよね ただ単に x=3のとき$((x))は$(($x))と「同じ値になる」とだけ。 だから例示されるスクリプトでも x=$(($x + 1)) みたいに書かれてる。 >>620 > x=$(($x + 1)) shellcheckではそれ不要だから外せって言われるよ? shellcheckが完璧だとは思わないけど、 あえてそうしてるんだからPOSIXだと思うんだけどなぁ >>616 あ、大丈夫みたいだよ。 コマンドも展開されるって書いてある $((expression)) The shell shall expand all tokens in the expression for parameter expansion, command substitution, and quote removal. あ、なるほど。わかった。 ${a} って書いたときの、aの部分が式なんだ。$は含まれない。それと同じで $((a)) もaの部分が式で>>623 に書いてあるように、先に展開される仕様だから $(($a))だと先に$aの部分が文字列として展開されて$((123))のように解釈される だから https://github.com/koalaman/shellcheck/wiki/SC2004 に書いてあるように > $ a='1+1' > $ echo $(($a * 5)) # becomes 1+1*5 > 6 これだと、式が評価される前に文字列として展開されちゃうから変な計算になるが > $ echo $((a * 5)) # evaluates as (1+1)*5 > 10 ${a}と同じように$((a))と書くと、ちゃんと算術演算が行われるんだ ということで、やっぱり$(($a))は間違いで$((a))が正しいようだね 間違いっていうのは仕様違反って意味じゃなくて 算術演算をするなら$をつけないのが正しいって意味ね。 算術演算の前に$とかコマンドが展開されるっていうのも 仕様なのでそれも書いたとおりに動作する 大きなファイルがいくつも入ったディレクトリのmvして分かったけど ファイルがいくつあっても全部のcpが終わったあとにrmされるんだね てっきり1ファイル毎かと思ってた >>626 途中で中止した時に移動先を削除するだけで済むからじゃないかな。 >>625 んー。でも俺には > If the shell variable x contains a value that forms a valid integer constant, > optionally including a leading or , > then the arithmetic expansions "$((x))" and "$(($x))" shall return the same value. は$((x))の「時だけ」$(($x))と等しいと読めるがな。 いずれにしても算術展開で算術計算をする際に変数を使いたいときは $(( ($x) + 1 )) にしてるわ。どっかで$(( x + 1 ))がエラーになるのが怖いので。 >>626 renameはアトミック操作にすべきって思想が強いから 違うファイルシステムにmvするときはそうだな $(())が展開できるものは限定されていて、$((x+1))が意図通りに展開される根拠は$((x))と$(($x))が等しいって書いてある一文しかない。 これは$(())の中だけはx=$xであると解釈できなくもないけど、算術演算をするなら$をつけないのが正しいとは読めないな。 > $((x+1))が意図通りに展開される根拠は$((x))と$(($x))が等しいって書いてある一文しかない。 一つあれば十分じゃん。逆に展開されない根拠はないんだし そもそも ${expression} と $((expression)) という記述があるんだから expressionの中は同じ意味のはずだろう > どっかで$(( x + 1 ))がエラーになるのが怖いので。 それがエラーになるなら、とっくに検出してるだろうな。 複数のシェルで確認してるからさ それ関連で注意が必要なのは $(($#-1)) zshだと81になる。 >>631 いや算術演算するときは$をつけないのが正しいとは何処にも書いてないけど というか,shellcheckでの検査結果うんぬんよりも本家POSIXの記述のほうが優先して考慮されるべきだと思うのだが。 本家POSIXに$((x))が動くと書いてあるだろ http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_04_01 に書いてあるだろ > Arithmetic expansion provides a mechanism for evaluating an arithmetic expression and substituting its value. > The format for arithmetic expansion shall be as follows: > > $((expression)) > > The expression shall be treated as if it were in double-quotes, except that a double-quote inside > the expression is not treated specially. The shell shall expand all tokens in the expression for > parameter expansion, command substitution, and quote removal. まず、$(( )) の中にある。これがexpressionだ。 expand all tokens in the expression 式の中にある以下のトークンの展開、 for parameter expansion, command substitution, and quote removal. パラメータ展開、コマンド置換、クォートの削除 > Next, the shell shall treat this as an arithmetic expression and substitute the value of the expression. その次(Next)に この式を arithmetic expression (算術式)として扱う つまりだ。パラメータ展開( $(($x))の$xの展開 )が行われるまでは、まだ算術式として扱う前なんだよ そもそもだな。 x=123を見て分かる通り。変数名はxだぞ。$xじゃない。 他の言語では変数名が$で始まるものがあるが、シェルスクリプトにおいて、 $は、パラメータ展開、コマンド置換、算術展開等を行うための記号だって書いてあるだろ? 特殊変数の説明だって、$@じゃなくて@、$*じゃなくて*、$#じゃなくて#、$$じゃなくて$ と書いており 変数名とは最初の$は含まれない部分だってことが読み取れるだろ >>637 あるからなんだよ? パラメータ展開が行われるから x=$(($x - 1)) は x=$((100 - 1)) となって動くだろうさ それは x=$((x - 1)) がだめな理由になってない >>638 発端は>>620 の > > x=$(($x + 1)) > > shellcheckではそれ不要だから外せって言われるよ? > shellcheckが完璧だとは思わないけど、 > あえてそうしてるんだからPOSIXだと思うんだけどなぁ これなんだが。 つまりx=$(($x + 1))の「$x」が不要という主張は完全に間違いってことだ。 x = $(($x - 1))とx = $((x - 1))のどっちが正しいかなんて言ってねえよ。 ただ,POSIXには前者の記載はあって後者はないから, shellcheckの「後者にしろ」っていう判定は絶対におかしい。 shellcheckは間違いだから不要と言ってるんじゃなくて、 意味がないから不要って言ってるんだよ。 お前コードチェックツールで変数が使われていませんって 指摘されたら、文法上は間違ってねーよって文句言うのかよ? > shellcheckの「後者にしろ」っていう判定は絶対におかしい。 後者にしろって言う判定は、前者が間違ってるって話じゃなくて、 後者もOK、だから後者はPOSIX違反ではない(POSIX違反を提案するわけがない)って話だよ もうちょっと落ち着けよ。お前否定されたらすぐカッとなるだろw > つまりx=$(($x + 1))の「$x」が不要という主張は完全に間違いってことだ。 > x = $(($x - 1))とx = $((x - 1))のどっちが正しいかなんて言ってねえよ。 後者が動くのであれば >「$x」が不要という主張は完全に間違い という主張の方が間違ってる。 そして後者は実際に動く だから前者が動かないなんていてないだろ 前者に$(($x -1))の$xの$が意味がないから (POSIX準拠で問題がない)後者の方が良いって話であって たまにいるんだよな。誰かにより良いコードの提案をされたら 俺の書いたコードが間違っているっていうんか、仕様どおりだ!って怒るやつ 仕様違反だとか間違ってるかどうかの話なんかしてない (正しいコードの範囲で)より良いコードにしましょうってことなのに すまん。怒らせるつもりは毛頭なかったんだわ。 ただ,「標準でははこうなってますよ」と示しただけ。 まあちょっと俺の言い方もキツかったな。 言い訳させてもらうと,今までPOSIXの仕様書も読まずに $(())算術展開は``に書き改めるべきとか,その割に[[文を使ってたりだとか そういう人間と多く議論してきて,こっちもかなり厳密さを求めるようになってしまっていた。 正直なところ仕様違反でもほとんどの環境で動くなら,別にそっちを使ってもいいかもね。 だから仕様違反じゃないつってるだろうが なんでこいつ理解能力無いんだろう? 冷静なふりして、冷静じゃないだろ $(($x - 1)) と $((x - 1)) のどちらも仕様違反じゃないのに $(($x - 1)) が動くってことは、 $((x - 1)) は仕様違反に違いニダ!って どういう思考回路なんだろ? $(($x - 1)) と $((x - 1)) は前者が先に$xのパラメータ展開が行われるため動作に違いがある https://github.com/koalaman/shellcheck/wiki/SC2004 に書いてあるとおり。 それはおそらく意図しないものだろうから警告される。 お前がPOSIXの仕様を読んでいない相手と議論してきたとか知らんが、 お前なんかよりも shellcheck の作者の方がよっぽどPOSIXの仕様に詳しいだろうよ なにせシェルスクリプトの構文解析機を作ってるし、 世界中から間違いがあったら指摘される立場にあるんだから Windows用の busybox.exe なんてものがあることをたった今知った。 こんなのあったんだな。 まあしかしよくよく考えてみればWindows用のgccとかのコンパイラでコンパイルすれば良いだけだからさほど凄いことではないか。 case "$(<なにかの処理>)" in 'A'|'aaa') echo 'B' ;; *) echo "$(<なにかの処理>)" ;; esac みたいな文でさ,<なにかの処理>を(できれば変数とか使わずに)一つにまとめたいんだけど できるかな。 "$(<なにかの処理>)"の結果が'A'か'aaa'の時のみ'B'を出力して,それ以外の場合はその処理のまんまを出力したい。 RESULT="$(<なにかの処理>)" case "$RESULT" in 'A'|'aaa') echo 'B' ;; *) echo "$RESULT" ;; esac でもいいんだけどな〜んか無駄がある気がするんだよね……近い場所で二回同じ変数使ってるっていうのが。 算術展開で$付けるのはナンセンスだからやめたほうがいい >>651 変数を使わないの書き方の基本の一つは引数(パラメータ)を使うことだよ 引数を変数の代わりとして使う。そのやり方に2パターンある ・パターン1 関数を作る(呼び出し先の関数の引数にする) foo() { case "$1" in 'A'|'aaa') echo 'B' ;; *) echo "$1" ;; esac } foo "$(<なにかの処理>)" ・パターン2 引数を再設定する(自分自身の引数にする) set -- "$(<なにかの処理>)" case "$1" in 'A'|'aaa') echo 'B' ;; *) echo "$1" ;; esac パターン2はこのままだと自分自身の引数がなくなってしまうが、 set -- "$(<なにかの処理>)" "$@" とすることで、残しておくことが可能。以降は引数の番号をずらして 扱うかshiftで元に戻すなりするか、引数の個数が固定なら、 set -- "$@" "$(<なにかの処理>)" と逆にしてもよい 余談だが、そんなコードを書くぐらいなら素直に変数を使えばいいと思うかもしれないが、 シェルスクリプトの変数がグローバル変数なのに対して、 引数は(レキシカルスコープ的な)ローカル変数になってるという重要な違いがある localやtypesetを使った変数のローカル化はダイナミックスコープなのでそれとも違う >>657 setって便利だよね 関数の最初に set -- $? "$@" として最後に return $1 とすれば終了コードも保存できるし。 ちょっと力を貸してほしい https://paste.ubuntu.com/p/hx6cFRKJKm/ 今、↑こういう引数処理を書いている。 動作としては $ ./argprs.sh -abc VAR -pqr FILE --long-opt --opt-req-par="foo bar" -- --not-opt 短いオプション1: a; 'VAR' 短いオプション2: b 短いオプション3: c 短いオプション4: p 短いオプション5: q 短いオプション6: r 被演算子1: FILE 長いオプション1: long-opt 長いオプション2: opt-req-par; 'foo bar' 被演算子2: --not-opt こういう出力ができるはず。つまり-aと--opt-req-parはパラメータを取って、--以降はオプションとして解釈されないっていうやつ。 ところが俺の知識量では短いオプションを解析する部分をすごく冗長にしか書けない。いちいちループを回すせいで遅いし。 動作自体はこれでいいので、短いオプションをもうちょっとうまく解析する方法とかないかな。 なんで、aのあとにVARくるんだ? 仕様がおかしくないか? VARが単体の値もしくは、-cの値っていうのならまだわかるんだが tarで試したが、これで動くのかよ・・・ tar czvf a.tar.gz a tar fczv a.tar.gz a パラメータ取る短いオプションが複数あったとき どう解釈するのが普通なんだろ getoptやgetoptsは短いオプションがパラメータを取るとき、 短いオプション以降がパラメータとみなされるようだ -abcde で cがパラメータを取るとき、 -a -b -c de と解釈される 実装によってバラバラなのは当然だろうが こっちのほうが楽だろうな >>660 の仕様だと、aとcがパラメータを取るとき -abcde VAR をどう解釈して良いのかわからない -abcde VAR1 VAR2 とすりゃいいのかもしれんが、 これは人間にとってわかりやすいんだろうか? ■ このスレッドは過去ログ倉庫に格納されています
read.cgi ver 07.5.5 2024/06/08 Walang Kapalit ★ | Donguri System Team 5ちゃんねる