1 名前:デフォルトの名無しさん mailto:sage [2018/09/22(土) 11:53:21.38 ID:BBiLRgnj0.net] !extend:on:vvvvv:1000:512 !extend:on:vvvvv:1000:512 シェルスクリプトに関する総合スレッドです。 スレ立て時は以下の文を先頭行に加えて下さい。 後のつけ忘れ防止の為に複数行重ねて追加推奨 !extend:on:vvvvv:1000:512 全般 ・荒しは無視しましょう。 ・丁寧な姿勢を心掛けましょう。 ・ネチケット(死語)を意識しましょう。 前スレ シェルスクリプト総合 その28 mevius.5ch.net/test/read.cgi/tech/1532397676/ VIPQ2_EXTDAT: default:vvvvv:1000:512:----: EXT was configured
626 名前:デフォルトの名無しさん [2018/11/14(水) 19:06:25.03 ID:vF6ts/2/r.net] 大きなファイルがいくつも入ったディレクトリのmvして分かったけど ファイルがいくつあっても全部のcpが終わったあとにrmされるんだね てっきり1ファイル毎かと思ってた
627 名前:デフォルトの名無しさん [2018/11/14(水) 19:23:07.48 ID:bryEJhFFa.net] >>626 途中で中止した時に移動先を削除するだけで済むからじゃないかな。
628 名前:デフォルトの名無しさん mailto:sage [2018/11/14(水) 19:34:11.25 ID:P8pvRdrO0.net] >>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 ))がエラーになるのが怖いので。
629 名前:デフォルトの名無しさん mailto:sage [2018/11/14(水) 21:35:28.76 ID:tEjpeAN9a.net] >>626 renameはアトミック操作にすべきって思想が強いから 違うファイルシステムにmvするときはそうだな
630 名前:デフォルトの名無しさん mailto:sage [2018/11/14(水) 21:50:05.93 ID:D6nmDs23M.net] $(())が展開できるものは限定されていて、$((x+1))が意図通りに展開される根拠は$((x))と$(($x))が等しいって書いてある一文しかない。 これは$(())の中だけはx=$xであると解釈できなくもないけど、算術演算をするなら$をつけないのが正しいとは読めないな。
631 名前:デフォルトの名無しさん mailto:sage [2018/11/14(水) 22:59:44.88 ID:Da4Ohzbn0.net] > $((x+1))が意図通りに展開される根拠は$((x))と$(($x))が等しいって書いてある一文しかない。 一つあれば十分じゃん。逆に展開されない根拠はないんだし そもそも ${expression} と $((expression)) という記述があるんだから expressionの中は同じ意味のはずだろう
632 名前:デフォルトの名無しさん mailto:sage [2018/11/14(水) 23:06:12.49 ID:Da4Ohzbn0.net] > どっかで$(( x + 1 ))がエラーになるのが怖いので。 それがエラーになるなら、とっくに検出してるだろうな。 複数のシェルで確認してるからさ それ関連で注意が必要なのは $(($#-1)) zshだと81になる。
633 名前:デフォルトの名無しさん mailto:sage [2018/11/15(木) 07:34:42.91 ID:CPG8nmHa0.net] >>631 いや算術演算するときは$をつけないのが正しいとは何処にも書いてないけど
634 名前:デフォルトの名無しさん mailto:sage [2018/11/15(木) 08:48:01.92 ID:sJsqi8La0.net] というか,shellcheckでの検査結果うんぬんよりも本家POSIXの記述のほうが優先して考慮されるべきだと思うのだが。
635 名前:デフォルトの名無しさん mailto:sage [2018/11/15(木) 10:49:23.03 ID:gWaB1LhD0.net] 本家POSIXに$((x))が動くと書いてあるだろ
636 名前:デフォルトの名無しさん mailto:sage [2018/11/15(木) 11:23:09.13 ID:gWaB1LhD0.net] 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 名前:デフォルトの名無しさん mailto:sage [2018/11/15(木) 11:44:50.73 ID:sJsqi8La0.net] >>636 そのすぐあとに x=$(($x - 1)) という記述があるんですが。 pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_04_01
638 名前:デフォルトの名無しさん mailto:sage [2018/11/15(木) 12:00:52.72 ID:gWaB1LhD0.net] >>637 あるからなんだよ? パラメータ展開が行われるから x=$(($x - 1)) は x=$((100 - 1)) となって動くだろうさ それは x=$((x - 1)) がだめな理由になってない
639 名前:デフォルトの名無しさん mailto:sage [2018/11/15(木) 12:27:06.72 ID:sJsqi8La0.net] >>638 発端は>>620 の > > x=$(($x + 1)) > > shellcheckではそれ不要だから外せって言われるよ? > shellcheckが完璧だとは思わないけど、 > あえてそうしてるんだからPOSIXだと思うんだけどなぁ これなんだが。 つまりx=$(($x + 1))の「$x」が不要という主張は完全に間違いってことだ。 x = $(($x - 1))とx = $((x - 1))のどっちが正しいかなんて言ってねえよ。 ただ,POSIXには前者の記載はあって後者はないから, shellcheckの「後者にしろ」っていう判定は絶対におかしい。
640 名前:デフォルトの名無しさん mailto:sage [2018/11/15(木) 12:34:01.42 ID:gWaB1LhD0.net] shellcheckは間違いだから不要と言ってるんじゃなくて、 意味がないから不要って言ってるんだよ。 お前コードチェックツールで変数が使われていませんって 指摘されたら、文法上は間違ってねーよって文句言うのかよ?
641 名前:デフォルトの名無しさん mailto:sage [2018/11/15(木) 12:36:27.53 ID:zXViJGdda.net] ファイッ
642 名前:デフォルトの名無しさん mailto:sage [2018/11/15(木) 12:36:35.34 ID:gWaB1LhD0.net] > shellcheckの「後者にしろ」っていう判定は絶対におかしい。 後者にしろって言う判定は、前者が間違ってるって話じゃなくて、 後者もOK、だから後者はPOSIX違反ではない(POSIX違反を提案するわけがない)って話だよ もうちょっと落ち着けよ。お前否定されたらすぐカッとなるだろw
643 名前:デフォルトの名無しさん mailto:sage [2018/11/15(木) 12:41:58.45 ID:gWaB1LhD0.net] > つまりx=$(($x + 1))の「$x」が不要という主張は完全に間違いってことだ。 > x = $(($x - 1))とx = $((x - 1))のどっちが正しいかなんて言ってねえよ。 後者が動くのであれば >「$x」が不要という主張は完全に間違い という主張の方が間違ってる。 そして後者は実際に動く
644 名前:デフォルトの名無しさん mailto:sage [2018/11/15(木) 13:09:09.63 ID:sJsqi8La0.net] 前者も実際に動くんですがそれは
645 名前:デフォルトの名無しさん mailto:sage [2018/11/15(木) 13:35:59.93 ID:gWaB1LhD0.net] だから前者が動かないなんていてないだろ 前者に$(($x -1))の$xの$が意味がないから (POSIX準拠で問題がない)後者の方が良いって話であって たまにいるんだよな。誰かにより良いコードの提案をされたら 俺の書いたコードが間違っているっていうんか、仕様どおりだ!って怒るやつ 仕様違反だとか間違ってるかどうかの話なんかしてない (正しいコードの範囲で)より良いコードにしましょうってことなのに
646 名前:デフォルトの名無しさん mailto:sage [2018/11/15(木) 14:51:03.70 ID:sJsqi8La0.net] すまん。怒らせるつもりは毛頭なかったんだわ。 ただ,「標準でははこうなってますよ」と示しただけ。 まあちょっと俺の言い方もキツかったな。 言い訳させてもらうと,今までPOSIXの仕様書も読まずに $(())算術展開は``に書き改めるべきとか,その割に[[文を使ってたりだとか そういう人間と多く議論してきて,こっちもかなり厳密さを求めるようになってしまっていた。 正直なところ仕様違反でもほとんどの環境で動くなら,別にそっちを使ってもいいかもね。
647 名前:デフォルトの名無しさん mailto:sage [2018/11/15(木) 14:58:36.45 ID:gWaB1LhD0.net] だから仕様違反じゃないつってるだろうが なんでこいつ理解能力無いんだろう? 冷静なふりして、冷静じゃないだろ
648 名前:デフォルトの名無しさん mailto:sage [2018/11/15(木) 15:08:37.91 ID:gWaB1LhD0.net] $(($x - 1)) と $((x - 1)) のどちらも仕様違反じゃないのに $(($x - 1)) が動くってことは、 $((x - 1)) は仕様違反に違いニダ!って どういう思考回路なんだろ? $(($x - 1)) と $((x - 1)) は前者が先に$xのパラメータ展開が行われるため動作に違いがある https://github.com/koalaman/shellcheck/wiki/SC2004 に書いてあるとおり。 それはおそらく意図しないものだろうから警告される。 お前がPOSIXの仕様を読んでいない相手と議論してきたとか知らんが、 お前なんかよりも shellcheck の作者の方がよっぽどPOSIXの仕様に詳しいだろうよ なにせシェルスクリプトの構文解析機を作ってるし、 世界中から間違いがあったら指摘される立場にあるんだから
649 名前:デフォルトの名無しさん mailto:sage [2018/11/15(木) 20:59:56.50 ID:8sDmawlrM.net] またvoid君かよ
650 名前:デフォルトの名無しさん [2018/11/16(金) 18:15:57.23 ID:4Z/2Zn+la.net] Windows用の busybox.exe なんてものがあることをたった今知った。 こんなのあったんだな。 まあしかしよくよく考えてみればWindows用のgccとかのコンパイラでコンパイルすれば良いだけだからさほど凄いことではないか。
651 名前:デフォルトの名無しさん mailto:sage [2018/11/16(金) 20:52:55.20 ID:0Fk/0vf10.net] case "$(<なにかの処理>)" in 'A'|'aaa') echo 'B' ;; *) echo "$(<なにかの処理>)" ;; esac みたいな文でさ,<なにかの処理>を(できれば変数とか使わずに)一つにまとめたいんだけど できるかな。 "$(<なにかの処理>)"の結果が'A'か'aaa'の時のみ'B'を出力して,それ以外の場合はその処理のまんまを出力したい。 RESULT="$(<なにかの処理>)" case "$RESULT" in 'A'|'aaa') echo 'B' ;; *) echo "$RESULT" ;; esac でもいいんだけどな〜んか無駄がある気がするんだよね……近い場所で二回同じ変数使ってるっていうのが。
652 名前:デフォルトの名無しさん [2018/11/16(金) 21:08:59.95 ID:4Z/2Zn+la.net] 気のせい
653 名前:デフォルトの名無しさん mailto:sage [2018/11/16(金) 23:08:25.02 ID:pv33BTTMM.net] 算術展開で$付けるのはナンセンスだからやめたほうがいい
654 名前:デフォルトの名無しさん [2018/11/16(金) 23:43:45.38 ID:HodhQ/sE0.net] いい感じのバカっぽさw
655 名前:デフォルトの名無しさん mailto:sage [2018/11/17(土) 00:11:39.03 ID:dLBGWOhBM.net] >>654 お前の書き込みがな
656 名前:デフォルトの名無しさん [2018/11/17(土) 00:41:14.93 ID:eQWBxdMf0.net] なんか悔しかったんかなw
657 名前:デフォルトの名無しさん mailto:sage [2018/11/17(土) 01:07:52.12 ID:LhPQgZnG0.net] >>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を使った変数のローカル化はダイナミックスコープなのでそれとも違う
658 名前:デフォルトの名無しさん mailto:sage [2018/11/17(土) 01:38:27.92 ID:dLBGWOhBM.net] >>656 お前が?w
659 名前:デフォルトの名無しさん mailto:sage [2018/11/17(土) 09:28:35.93 ID:XLrbbNN30.net] >>657 setって便利だよね 関数の最初に set -- $? "$@" として最後に return $1 とすれば終了コードも保存できるし。
660 名前:デフォルトの名無しさん mailto:sage [2018/11/17(土) 18:51:09.82 ID:ikDL4PRg0.net] ちょっと力を貸してほしい 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はパラメータを取って、--以降はオプションとして解釈されないっていうやつ。 ところが俺の知識量では短いオプションを解析する部分をすごく冗長にしか書けない。いちいちループを回すせいで遅いし。 動作自体はこれでいいので、短いオプションをもうちょっとうまく解析する方法とかないかな。
661 名前:デフォルトの名無しさん mailto:sage [2018/11/17(土) 19:14:04.69 ID:DG9kgnl30.net] なんで、aのあとにVARくるんだ? 仕様がおかしくないか? VARが単体の値もしくは、-cの値っていうのならまだわかるんだが
662 名前:デフォルトの名無しさん [2018/11/17(土) 19:19:32.18 ID:eQWBxdMf0.net] エクセルマクラーと同じ病気やね
663 名前:デフォルトの名無しさん mailto:sage [2018/11/17(土) 19:49:25.15 ID:DG9kgnl30.net] tarで試したが、これで動くのかよ・・・ tar czvf a.tar.gz a tar fczv a.tar.gz a パラメータ取る短いオプションが複数あったとき どう解釈するのが普通なんだろ
664 名前:デフォルトの名無しさん mailto:sage [2018/11/17(土) 20:09:39.20 ID:DG9kgnl30.net] getoptやgetoptsは短いオプションがパラメータを取るとき、 短いオプション以降がパラメータとみなされるようだ -abcde で cがパラメータを取るとき、 -a -b -c de と解釈される 実装によってバラバラなのは当然だろうが こっちのほうが楽だろうな >>660 の仕様だと、aとcがパラメータを取るとき -abcde VAR をどう解釈して良いのかわからない -abcde VAR1 VAR2 とすりゃいいのかもしれんが、 これは人間にとってわかりやすいんだろうか?
665 名前:デフォルトの名無しさん [2018/11/17(土) 20:18:41.59 ID:eQWBxdMf0.net] バカは考えるだけムダやぞw
666 名前:デフォルトの名無しさん mailto:sage [2018/11/17(土) 20:23:56.08 ID:UtANxJrV0.net] >>663 tarはハイフン無しでオプションを書くといい感じに並べ替えてくれる
667 名前:デフォルトの名無しさん mailto:sage [2018/11/17(土) 20:45:00.33 ID:ikDL4PRg0.net] つまり -aVAR -xyza VAR みたいなのは許容して -axyz VAR は許容しないようにすればいいのかな。 まあ結局一文字オプションを扱う方法はくっそ遅いルーチンなのだがw
668 名前:660 mailto:sage [2018/11/17(土) 21:16:27.44 ID:ikDL4PRg0.net] こうしてみました。 短いオプションの解析ルーチンの遅さは改善してませんが 値を取るオプションの解釈を皆さんから提示された方式に変えました。 https://paste.ubuntu.com/p/n7m8qZHwMb/
669 名前:デフォルトの名無しさん [2018/11/17(土) 21:33:05.69 ID:eQWBxdMf0.net] >>668 提示てwバカにされとんのやぞおまえw
670 名前:デフォルトの名無しさん mailto:sage [2018/11/17(土) 22:38:36.24 ID:ikDL4PRg0.net] こういういったシェルスクリプトを書くの大変なので自動的に生成してくれるのがあればいいですけどね。 Pythonのdocoptみたいな。
671 名前:デフォルトの名無しさん [2018/11/17(土) 22:57:50.85 ID:eQWBxdMf0.net] >>670 そういったシェルはそもそも必要とされとらんのやぞ 出来るからといってやりすぎになるのはバカの悪癖やw 改めた方がええでおまえw
672 名前:デフォルトの名無しさん mailto:sage [2018/11/17(土) 23:25:40.65 ID:4Do7jDVB0.net] ふつーに、getopts でええやん! 入力補完を使ったら、別にコマンドが長くてもわかりやすさ優先でかまへんわ。
673 名前:デフォルトの名無しさん mailto:sage [2018/11/17(土) 23:58:26.07 ID:2WlUsnTW0.net] Ruby にも、OptionParser, ARGV.getopts などのモジュールがあるので、自作などしない
674 名前:デフォルトの名無しさん mailto:sage [2018/11/18(日) 00:47:33.69 ID:tOYW/MHy0.net] >>667 遅い原因はcutを使うからなんだけどねw >>668 __cnt_opd__のせいでごちゃごちゃしてる。 なんに使ってるかと思ったら、番号出してるだけだよな? オプションは普通順番には依存しないので最終的には不要なはずだ。 逆に分かりづらくなるから、こういうのは書かないほうが良いぞ もしくはその部分を関数に分離してそっちでカウントするとか あと並べ替えてもいいんだな >>670 よし、作るんだ! >>673 作者「なかったから自作したんやで」
675 名前:デフォルトの名無しさん mailto:sage [2018/11/18(日) 01:05:23.45 ID:tOYW/MHy0.net] >>668 とりあえず邪魔なんで、本質的なコードと、どうでも良いコードは分けた https://paste.ubuntu.com/p/DRf6Nzz8kM/
676 名前:デフォルトの名無しさん mailto:sage [2018/11/18(日) 01:17:46.87 ID:tOYW/MHy0.net] 余計な変数を消したり、被演算子の部分を外出ししたりした https://paste.ubuntu.com/p/p7VwzJZ8Hv/ あとオレがリファクタリングするときによくやるんだが、 (他人の)リファクタリングする前のコードは長いことが多い 全体を把握しやすくするためにあえて一行にしたりして短くしている。 最終的にこのような書き方をするというわけではなくて一時的な処置
677 名前:デフォルトの名無しさん mailto:sage [2018/11/18(日) 01:19:40.72 ID:tOYW/MHy0.net] あと、これもしたな。こんな部分、あとでどうとでもなるんだからここでやることじゃない 長いオプション1: long-opt 長いオプション2: opt-req-par; 'foo bar' ↓ 長いオプション1: --long-opt 長いオプション2: --opt-req-par; 'foo bar'
678 名前:デフォルトの名無しさん mailto:sage [2018/11/18(日) 01:21:35.58 ID:dx8aUZPH0.net] caseの後の変数はダブルコーテーションで括らなくていいって知ってた?
679 名前:デフォルトの名無しさん mailto:sage [2018/11/18(日) 01:26:08.97 ID:tOYW/MHy0.net] 長いオプションの部分をフラットにした。 https://paste.ubuntu.com/p/Y4nTQBnTFw/ あとはクソめんどくさい一文字の部分だな。 どうするか考えとらんのだがw 仕様は変えるかもしれん。
680 名前:デフォルトの名無しさん mailto:sage [2018/11/18(日) 01:27:00.28 ID:tOYW/MHy0.net] >>678 うん。だから徐々に消してるよw
681 名前:デフォルトの名無しさん mailto:sage [2018/11/18(日) 01:28:24.11 ID:tOYW/MHy0.net] あ、いくつかパっと見でわかるミスがw まあ途中のコードは参考だから 俺がどうやってリファクタリングしているか
682 名前:デフォルトの名無しさん mailto:sage [2018/11/18(日) 02:04:33.63 ID:tOYW/MHy0.net] とりあえずは大まかな仕様は変えてない https://paste.ubuntu.com/p/SQFnqmCJs2/ 変数をなくそうか、でもそうすると再帰ありの関数を追加するか setを使わないといけなくてごちゃごちゃする。 いろいろ悩んだがとりあえずそのままにしている。 cutの呼び出しはなくしたので速くなってるはず。 といっても、この程度だとLinuxなら体感できないはずなんだがWSLでやってる? 1文字オプションの分解の所がやはり面倒だな。 知らないオプションはエラーにするようにすれば、 1文字を抜き出す必要はなくなるかもしれないが
683 名前:デフォルトの名無しさん mailto:sage [2018/11/18(日) 02:13:58.54 ID:tOYW/MHy0.net] >>670 > Pythonのdocoptみたいな。 あと一応あるで https://github.com/docopt/docopts goバイナリでオプション解析して、シェルスクリプトで evalできるコードを出力して、そのコードで環境変数を 設定するという仕組みで、純粋なシェルスクリプト実装ではないけど
684 名前:デフォルトの名無しさん mailto:sage [2018/11/18(日) 02:21:13.13 ID:tOYW/MHy0.net] ちなみにオプション解析の部分は一般的に最初に一回だけ行う部分なので 被らないようにしたり、無理して変数をなくす必要はないんだけどね
685 名前:デフォルトの名無しさん mailto:sage [2018/11/18(日) 17:17:51.79 ID:Fz4U8sel0.net] >>674 オプションの番号は,競合するオプションが指定された時に後者を優先する目的です。 rm -i -f としたときに「確認する」のではなく「強制的に消し」たいので。 alias rm='\rm -i' の状態でrm -fとしたときは確認オプションが有効になるんじゃなくて強制的に消去したいよね?
686 名前:デフォルトの名無しさん mailto:sage [2018/11/18(日) 17:19:37.66 ID:Fz4U8sel0.net] >>682 エスパーかな? その通り。WSLでやってる。なるほどLinuxネイティブではcutを一文字ごとに呼び出しても十分早いのかな?
687 名前:デフォルトの名無しさん mailto:sage [2018/11/18(日) 17:23:02.81 ID:Fz4U8sel0.net] 連投すまん。 ちなみにどうやら汎用性のあるシェルスクリプトではローカル変数というのはsetを使わない限り実現できないようで, そしてsetは今まさに解析すべき引数郡がが格納されているので安易に書き換えられない。 だからPythonの慣例を参考にして前後にアンダースコアを二つ続けて(無意味だけど)ローカル変数であることを示してるつもり。
688 名前:デフォルトの名無しさん mailto:sage [2018/11/18(日) 17:35:21.66 ID:Fz4U8sel0.net] ${numbar:-0}←これすごいアイデアですね。 シェルスクリプトの冒頭でnumber=0とかで初期化しなくても、 「カウンターを初期化するのは値が設定されてないときである」ことを利用して変数展開を行なうのか。
689 名前:デフォルトの名無しさん mailto:sage [2018/11/18(日) 17:59:50.57 ID:tOYW/MHy0.net] >>685 > オプションの番号は,競合するオプションが指定された時に後者を優先する目的です。 それなら変数に入れておけば良いんだよ。 競合するオプションなら、変数を同じにしておけば良い 基本的に「オプションの解析」では変数に値を入れるのみ その場で処理はしない。変数に入れた値が後者で上書きされるから 必然的に後者が優先される > その通り。WSLでやってる。なるほどLinuxネイティブではcutを一文字ごとに呼び出しても十分早いのかな? time dash -c 'i=0; while [ $i -lt 1000 ]; do echo a | cut -c 1 > /dev/null; i=$((i+1)); done' Linuxでこれを実行すると約1秒。WSLでこれを実行すると15秒。fork(サブプロセス生成)が行われるとこれだけの差がでる 元々forkは遅いのだが、WSL上だと更に輪をかけて遅くなるのがわかる これをforkなしのシェルだけで実行できる同等のコードに置き換えるとWSLで50ミリ秒に減る。Linuxだと20ミリ秒にへる time dash -c 'i=0; while [ $i -lt 1000 ]; do v=abc; v=${v%"${v#?}"}; echo $v >/dev/null ; i=$((i+1)); done' もっともforkなしのコードは万能ではなく、文字列の最初の一文字を取るために「文字列の最初の一文字を取り除いた残り」を 求めてから、全体から抜き取っているために、文字列が長くなると極端に遅くなる。 文字列を1文字ずつ処理するコードを書いたとして、1000文字〜1万文字程度が限界。(数秒〜数十秒かかる) それ以上の長さの文字列を1文字ずつ処理するコードを書くならsedあたりで1文字ずつに分解して処理したほうが良いだろう POSIX準拠しなくていいなら${v:0:1} を使ったほうが速いと思う(計測はしてない) だけど一般的なオプション程度の長さであれば十分速い。少なくともcutを使うよりも遅くなることはないだろう
690 名前:デフォルトの名無しさん mailto:sage [2018/11/18(日) 18:05:11.85 ID:tOYW/MHy0.net] >>668 今回は長いコードが邪魔だったので使ったけど、 例えばnumberが環境変数としてexportされていたりしたら おかしいことになるので最初に初期化するほうが良いけどね 毎回パラメータ展開してるからわずかとはいえ遅くなるだろうし それよりも、所見では使い道がわからない ${var:+value}の方が凄いアイデア シェルを作った人はよくもまあこんな応用例が 高いものを作ったもんだと思うよ
691 名前:デフォルトの名無しさん mailto:sage [2018/11/18(日) 23:06:30.15 ID:Fz4U8sel0.net] test <string>は<string>が非空に限り成功するのね。これも知らんかったわ……。
692 名前:デフォルトの名無しさん mailto:sage [2018/11/21(水) 17:53:42.80 ID:OLor19Fe0.net] しつこくてすまん。 シェルスクリプトの引数解析の話なんだが (-cが引数を取るオプションとして) 「$ somecmd -c -- --not-a-opt」 っていうコマンドラインにおいて, ・「--」を-cオプションの引数として見るか ・「--」はいかなる場所(オプションの引数の位置だとしても)においても 以降が被演算子であることを示すものであると見るか どっちが自然だろう。GNU getoptは前者の解析結果を出すけど恐らく内部的には後者の解釈で エラーになる。
693 名前:デフォルトの名無しさん mailto:sage [2018/11/21(水) 18:33:47.11 ID:UM5ff+tU0.net] 引数取るなら何であれ引数に決まってるだろ どうでもいいけどさ、その被演算子ってのやめてくんない? 演算子なんて登場してないんだから
694 名前:デフォルトの名無しさん mailto:sage [2018/11/21(水) 18:55:25.78 ID:OLor19Fe0.net] operandって被演算子のことだと思うんだけど。 まあ「--」を引数と見るってことね。ありがとう。
695 名前:デフォルトの名無しさん mailto:sage [2018/11/21(水) 19:16:12.30 ID:UM5ff+tU0.net] だからそのoperandが出てこないって話
696 名前:デフォルトの名無しさん mailto:sage [2018/11/21(水) 20:33:17.21 ID:cLxfY5McM.net] operand https://wa3.i-3-i.info/word13306.html
697 名前:デフォルトの名無しさん mailto:sage [2018/11/21(水) 21:01:13.07 ID:UM5ff+tU0.net] >>696 はい。どうも。 exprとか引数が何かしらの式であるものは 演算子以外の部分が被演算子(オペランド)になることはありえるけど なんでもかんでもオペランドなわけではないよね
698 名前:デフォルトの名無しさん mailto:sage [2018/11/21(水) 21:31:00.38 ID:OLor19Fe0.net] ああ。ほんとだ。The Open Groupの文書を参考にする限り somecmd -c XXX FILE とあった場合被演算子はFILEでXXXはオプション引数だね。勘違いしてた。
699 名前:デフォルトの名無しさん mailto:sage [2018/11/24(土) 12:14:20.49 ID:I8hvszb00.net] Qiitaで知ったけどこの構文便利だね。 ${VAL+:} false ↑これで$VAL変数が空文字だろうが定義されてさえいれば真,そうでなけば偽。 今まで[ -n ]と[ "x$VAL" = "$VAL:-x" ]とか組み合わせてたけどこれでスッキリ解決。 コマンド呼び出しも少なくなるから微妙に処理速度も上がるだろうし。 ただ難点は,test構文を用いた方法より遥かに難読になること。${VAL+:} false←これで何をやってるかなんて注釈がないと分からん。
700 名前:デフォルトの名無しさん mailto:sage [2018/11/24(土) 12:41:53.30 ID:emfrr2Lm0.net] >>699 なんだそりゃ? 相変わらずのQiitaクオリティなのか? 変数が定義されているかの一般的なチェック方法はこれだろ? [ "${VAR+1}" ]
701 名前:デフォルトの名無しさん mailto:sage [2018/11/24(土) 14:04:21.10 ID:jPqivsUqa.net] 定義されてるかどうかってどういう時に用いるんだ C言語やってた頃は二重インポート防ぐためとかやってたけど同じような感じ?
702 名前:デフォルトの名無しさん mailto:sage [2018/11/24(土) 14:31:59.62 ID:I8hvszb00.net] >>700 「一般的」かどうかは知らない。それともその形式がより多く使われているという根拠があるのかな? いずれにしてもコロンコマンド(と変数展開)がシェルのビルトインとしてPOSIXで定められているのに対して testコマンドはPOSIXにおいては外部コマンド。尤もBashやZshではシェルに組み込まれてるけど。 外部コマンドを呼び出すのとシェルの内部でコマンドを展開するとでは後者のほうが早いよ。 君にとっては「Qittaクオリティ」でも,速度が優秀なのは君が提示したほうじゃなく「Qittaクオリティ」の方。
703 名前:デフォルトの名無しさん mailto:sage [2018/11/24(土) 14:49:43.89 ID:I8hvszb00.net] dashでも[はシェル組込だね。実際testユーティリティを外部コマンドに頼ってるシェルって今現在存在しているのだろうか。 Heirloom shellあたりだとありえそう(試してないけど)
704 名前:デフォルトの名無しさん mailto:sage [2018/11/24(土) 15:54:11.31 ID:emfrr2Lm0.net] > 「一般的」かどうかは知らない。それともその形式がより多く使われているという根拠があるのかな? ぐぐればコレばっかり見つかるはずだが? > testコマンドはPOSIXにおいては外部コマンド。尤もBashやZshではシェルに組み込まれてるけど。 全てのシェルで [ はビルトインだ シェルに組み込まれていないというものがあれば教えてくれ
705 名前:デフォルトの名無しさん mailto:sage [2018/11/24(土) 16:18:05.53 ID:emfrr2Lm0.net] falseコマンドはPOSIXでシェルのビルトインではない もっともどのシェルでもビルトインになっているが
706 名前:デフォルトの名無しさん mailto:sage [2018/11/24(土) 17:26:54.56 ID:I8hvszb00.net] >>704 > ググればこればっかり ほう,それは知らなかった。pws=0にしたGoogle検索英語版では${VAR+:}が多いように見受けられるな。 > 全てのシェルで[はビルトイン test(1)ユーティリティは,あくまでPOSIXにおいて組込ユーティリティじゃないという話。 根拠はこれ: pubs.opengroup.org/onlinepubs/9699919799/idx/sbi.html > シェルに組み込まれていないというものがあれば教えてくれ ご査収ください→https://www.unix.com/man-page/v7/1/sh/#neo-man-page-output
707 名前:デフォルトの名無しさん mailto:sage [2018/11/24(土) 17:36:50.26 ID:b7tmfxF40.net] >>706 falseがビルトインって話じゃなかったの?w
708 名前:デフォルトの名無しさん mailto:sage [2018/11/24(土) 17:38:22.47 ID:b7tmfxF40.net] > ほう,それは知らなかった。pws=0にしたGoogle検索英語版では${VAR+:}が多いように見受けられるな。 "${VAR+:}"で検索したけど5件しかなかったよ? "${VAR+x}"だと約 3,410,000 件
709 名前:デフォルトの名無しさん mailto:sage [2018/11/24(土) 17:41:59.00 ID:I8hvszb00.net] ちなみに「すべてのシェル」と言うくらいなのだから, 主要でありPOSIX互換を謳うGNU Bash, Zsh, Debian Almquist shell(dash), yash, MirOS ksh(mksh)くらいについては知らべてるとは思うものの, POSIXの記述を知らないようなので, 一応,これら5つのシェルがtest(1)ユーティリティを組込コマンドにしているという根拠を以下に挙げておこう。 GNU Bash: https://www.gnu.org/software/bash/manual/html_node/Bourne-Shell-Builtins.html#Bourne-Shell-Builtins Zsh: zsh.sourceforge.net/Doc/Release/Shell-Builtin-Commands.html#Shell-Builtin-Commands dash: man7.org/linux/man-pages/man1/dash.1.html yash: https://yash.osdn.jp/doc/ja/#alpha-order mksh: https://www.mirbsd.org/htman/i386/man1/mksh.htm
710 名前:デフォルトの名無しさん mailto:sage [2018/11/24(土) 17:44:33.96 ID:I8hvszb00.net] >>707 以下>>704 の書き込みを引用 > > testコマンドはPOSIXにおいては外部コマンド。尤もBashやZshではシェルに組み込まれてるけど。 > 全てのシェルで [ はビルトインだ > シェルに組み込まれていないというものがあれば教えてくれ ということでfalse(1)ユーティリティの話ではなく test(1)ユーティリティがシェル組込みかどうかという話でした。
711 名前:デフォルトの名無しさん mailto:sage [2018/11/24(土) 17:47:23.27 ID:I8hvszb00.net] ちなみにfalse(1)ユーティリティもPOSIXにおいてシェル組込みとして定められている訳ではない。
712 名前:デフォルトの名無しさん mailto:sage [2018/11/24(土) 17:49:01.92 ID:362BcdsM0.net] となると処理速度的にはどっちが良いの?
713 名前:デフォルトの名無しさん mailto:sage [2018/11/24(土) 17:50:38.66 ID:b7tmfxF40.net] いや、俺が言ったことを復唱されてもこまるんだがw ちなみにビルトインかどうかはPATHを空にして実行できるかどうかでわかるよ builtinやtypeがないシェルもあるからね
714 名前:デフォルトの名無しさん mailto:sage [2018/11/24(土) 17:51:02.76 ID:b7tmfxF40.net] >>712 大差なし
715 名前:デフォルトの名無しさん mailto:sage [2018/11/24(土) 18:05:17.83 ID:I8hvszb00.net] >>712 大差ないけど,ただ,もしもPOSIXで定めらていないのを理由にしてtest(1)ユーティリティを組み込んでいないシェルがあったとして そのシェルにおいては変数展開(これは確実にシェルが仕事する)のほうがtest(1)ユーティリティをforkしてexecするより若干早いので 速度は${VAR+:}のほうが上。
716 名前:デフォルトの名無しさん mailto:sage [2018/11/24(土) 18:06:48.53 ID:I8hvszb00.net] >>713 typeはPOSIXで定められているので,もしないシェルがあればPOSIX互換ではない。 つまり「ビルトインコマンド」なんていう概念はないかもしれないので,そんなことを調べるのは無駄に思えるな。
717 名前:デフォルトの名無しさん mailto:sage [2018/11/24(土) 19:13:13.38 ID:b7tmfxF40.net] へー、poshはPOSIX互換じゃなかったのか >Debian Policy に準拠した普通のシェル >posh は、pdksh の軽装版であり、Debian ポリシーの準拠を目指し、 いくつかの特別な機能を付け加えたものです。 > >警告: Debian の /bin/sh スクリプトの多くは、実際はポリシーに準拠していると は限りませんので、 >posh を /bin/sh として使うと破損箇所が判明するかもしれま せん。 って書いてある割に大したことないな
718 名前:デフォルトの名無しさん mailto:sage [2018/11/24(土) 20:44:49.31 ID:I8hvszb00.net] まあ ここまでPOSIX POSIX連呼しときながらアレだけども, 別にシェルってPOSIX shに準拠してる必要性なんてまったくないよなw poshも「POSIX互換じゃないシェル」として,便利に使えるようになればそれでいい。 実際,俺は使っていないものの,同級生にはfishを勧めてる。
719 名前:デフォルトの名無しさん mailto:sage [2018/11/24(土) 20:55:10.29 ID:32uSmIhta.net] ポジクッス警察がいるから多少はね?
720 名前:デフォルトの名無しさん mailto:sage [2018/11/24(土) 20:57:06.31 ID:b7tmfxF40.net] それじゃ俺も言っておかなきゃいかんのか? まあ ここまでPOSIX POSIX連呼しときながらアレだけども, 別にシェルってPOSIX shに準拠してる必要性なんてまったくなくて POSIXに準拠していなくても、現実にPOSIX互換の標準シェルとして デフォルトシェルで採用されているのであればそれに対応すべきだと思っている だから、dash、(busybox)ash、bash、ksh あたりは対応必須で zsh、posh、yash、あたりは優先度が低い。mksh、pdkshは デフォルトシェルとして採用されている事例があるのかわからんが
721 名前:デフォルトの名無しさん mailto:sage [2018/11/24(土) 20:58:50.94 ID:b7tmfxF40.net] 俺は現実主義なんでね。標準とか仕様がどうこうよりも 現実としてそれは選択肢にならないのであれば、選択肢にならないし 非標準でも選択肢としてなり得るのならそれを使う
722 名前:デフォルトの名無しさん mailto:sage [2018/11/24(土) 23:48:23.42 ID:u7Q7GReoM.net] ポジコレ棒で葬ってやんよ
723 名前:デフォルトの名無しさん mailto:sage [2018/11/25(日) 07:40:30.00 ID:rsPEFWOD0.net] もっと面白い書き込みして、どうぞ。
724 名前:デフォルトの名無しさん mailto:sage [2018/11/25(日) 12:05:00.87 ID:Yow09MRJ0.net] >>715 その前提条件で言えば false も組み込みじゃないかもしれないのだから同じじゃないの? 変数が定義されていれば false は実行されないけど、未定義かどうかを確認したいから 実行するわけで。 ただ、fork and exec に関して言えば test コマンドが 1.1ms, false コマンド は 0.8ms 程度 (コマンドバイナリのテキストセクションがメモリキャッシュされている場合で、実行環境は Intel Xeon E3-1220 3.1GHz/Linux kernel 4.15.0/glibc 2.27)。何千回も実行する様なケース なら違いが分かるかも。
725 名前:デフォルトの名無しさん mailto:sage [2018/11/25(日) 12:16:11.88 ID:wMoGqmE60.net] POSIXでビルトインの方が速いって決まってるんだっけ?
726 名前:デフォルトの名無しさん mailto:sage [2018/11/25(日) 12:29:43.54 ID:nRWf72Y30.net] >>725 外部コマンドはforkが発生するから結果的にビルトインの方が速い