シェルスクリプト総合 その28
■ このスレッドは過去ログ倉庫に格納されています
シェルスクリプトの総合スレです。 □お約束 ・特記なき場合は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に逃げずにシェルスクリプトで処理するのが頭のいいやり方。 質問に対して問題が間違ってるといちゃもんをつけるのもやめましょう シェルスクリプト総合 その27 https://mevius.5ch.net/test/read.cgi/unix/1525337663/ 流れとか関係なくどこまで知っているのか想定もせず、 偉ぶれると思ったら食いつくいつもの馬鹿だろな 口は悪いけどみんなと仲良くしたいだけなんです大目に見てあげてください >>470 おまえこそ、いつものマウンターマウンターだな。w >>466 ,467 どーも。 やっぱそうか。。。 -o substfailとかあってもいいのに。 >>467 > そっちはやってる うん、書かなかったけど、やってはみてた。 でもやめた。 なんかひっかかるし、いずれ誤って直しそうだし。 declare/set/exportで書いたら失敗が無視されることも気になる。 だからさ、もう結論出てるんだよ var=$(...) echo "$var" | sed ... こう書けば終わり sedのホールドスペースは、その内容を削除するにはどうすれば? とりあえずs/.//g;xでできたけど、もっと直接的なやりかたはないんかなー、と。 怪しげなシェル芸が宣伝中 【広告記事】今、ユニケージ開発手法にギークが熱狂するワケ【USP研究所代表&オープンソースOSコミッター対談】 ttps://type.jp/et/feature/14070/ 空白行でいくつかのブロックに分割されたテキストにて、 文字列にマッチするブロックを出力する方法を探してます たとえば 111 222 222 aaa 222 333 333 333 のようなテキスト中から、aaaを検索した際に、その前後の空白行に囲まれたブロックである 222 222 aaa 222 という結果を得たいです いまは最初にブロックごとに一時ファイルを作り、それぞれに対してgrepにて検索し マッチしたファイルを出力、としているのですがブロックが20万ほどあり、 分割も検索も遅くて困ってます 該当するブロックは3〜5個程度なので、むしろgrepでマッチする行番号を調べる →テキストをless等でひらき該当行へジャンプ →そのブロックをコピペ の方が早いくらいでして Linux板くだ質スレでいい加減嫌われたから流れてきたって感じかな > ブロックが20万ほどあり この時点でデータ構造の方を考え直すべき \n\n(\n...)ではない \nをスペース(やタブなど)に | grep '\<aaa\>' | スペース(やタブなどにしたの)を\nに テキトーに色々 $ for i in {1..2000000}; do echo aaaa; echo bbbb; echo cccc; echo $i; echo dddd; echo eeee; echo ffff; echo gggg; echo; done > aaa $ time (awk 'function keepp () { if (matched) { for (i=0 ; i < nkeeps ; i++) print keeps[i]; print } matched=0; nkeeps=0 } NF == 0 { keepp(); next } { keeps[nkeeps++]=$0; if ($1 == "1414213") matched=1 } END{ keepp() }' < aaa ) real 0m10.556s user 0m10.281s sys 0m0.271s $ time (awk 'NF == 0 { print; next } { printf "%s ", $0 }' < aaa | grep '\<1414213\>' | tr ' ' '\n') real 0m11.101s user 0m1.177s sys 0m12.259s $ time (tr '\n' ' ' < aaa | sed -e 's/ /\ /g' | grep '\<1414213\>' | tr ' ' '\n') real 0m2.344s user 0m1.452s sys 0m0.814s $ time (tr '\n' ' ' < aaa | sed -e 's/ */\ /g' | grep '\<1414213\>' | tr ' ' '\n') real 0m3.678s user 0m1.484s sys 0m1.078s $ time sh smf1.sh real 0m4.088s user 0m2.324s sys 0m3.803s $ cat smf1.sh #!/bin/sh SMF=/tmp/xxx [ ! -x $SMF ] && { cc -x c - -o $SMF << 'EOS' #include <stdio.h> #include <stdlib.h> #include <string.h> int main(int argc, char *argv[]) { const size_t BUFFER_SIZE = 1024 * 1024 + 1; char *buffer = (char *)malloc(BUFFER_SIZE); while (fgets(buffer, BUFFER_SIZE, stdin) != NULL) { char *ep = buffer + strlen(buffer) - 1; if (ep >= buffer && *ep == '\n') *ep = '\0'; if (buffer[0] == '\0') putc('\n', stdout); else printf("%s ", buffer); } return 0; } EOS [ $? -ne 0 ] && exit 1; } $SMF < aaa | grep '\<1414213\>' | tr ' ' '\n' $ time sh smf2.sh real 0m0.717s user 0m0.381s sys 0m0.436s #!/bin/sh SMF=/tmp/xxx [ ! -x $SMF ] && { cc -x c - -o $SMF << 'EOS' #include <stdio.h> #include <stdlib.h> #include <string.h> int main(int argc, char *argv[]) { const size_t BUFFER_SIZE = 1024 * 1024; char *srcbuff = (char *)malloc(BUFFER_SIZE); char *dstbuff = (char *)malloc(BUFFER_SIZE+1); char *const de = dstbuff + BUFFER_SIZE - 1; int numLFs = 0; size_t len; while ((len = fread(srcbuff, 1, BUFFER_SIZE, stdin)) > 0) { char *sp = srcbuff; char *const sep = sp + len - 1; char *dp = dstbuff; char c; while (sp <= sep) { if ((c = *(sp++)) == '\n') numLFs++; else{ if (numLFs > 1) *(dp++) = '\n'; else if (numLFs == 1) *(dp++) = ' '; numLFs = 0; *(dp++) = c; } } fwrite(dstbuff, 1, (size_t)(dp - dstbuff), stdout); } return 0; } EOS [ $? -ne 0 ] && exit 1; } $SMF < aaa | grep '\<1414213\>' | tr ' ' '\n' 481です いろいろな方法について情報ありがとうございます 参考にさせていただき、取り入れていこうと思います 特定の文字列で始まるファイルが存在するかの判断はどうすればいいでしょうか ぐぐって見つけた ls を使う方法 if ls $f* > /dev/null 2>&1 then echo $f で始まるファイルがあります fi だと該当ファイルが存在しない場合に ...にアクセスできません: そのようなファイルやディレクトリはありません というエラーメッセージが表示されます。 また、 for g in $f* ; do echo $f で始まるファイル $g があります done だと該当ファイルがない場合でもループの中に入ってしまいます。 >>489 zshでじゃないの そういう余計なオプション(nomatch)がデフォでオンになってるのでオフにする setopt nonomatch >>489 あと、forの場合は、シェルが対象がなくてglob展開できない場合はglobそのままの値となる。forの場合に限らずglobはそういうもの for g in $f* の場合は、g が $f* になるので、展開されずにそのままなのかチェックするのは必要 for g in $f*; do [ "$g" = "$f*" ] && { echo 展開できませんでした; break; } な感じで >forの場合に限らずglobはそういうもの なので、 if [ "$(echo $f*)" != "$f*" ] then echo $f で始まるファイルがあります fi とかとも書ける zshでnomatchだと余計なメッセージが出るし、>>489 のls使ってる方が見た目なにしたいのかわかりやすいと思うけど、いちおう >>492 ああ、念のためには元globとの比較ではなくて -e する方がいいな [ "$g" = "$f*" ] でなくて [ -e "$g" ] zshネタ、シェルスクリプトではなくて zsh script になってしまうが null_glob ってのもあるんだな setopt null_glob ってすると、エラーメッセージは出ないわ、globに当てはまらない場合globを入れない/消すわで、>>489 のどっちも動くようになるな そんな応えは求めてないだろうけどw ああ、bashにもnullglobって同じようなのがあるのか シェルスクリプトという汎用ではなく各シェル固有独特の機能なので使わないだろけど そして、bashにも failglob ってあるのか。オンになってたら>>489 はbashでも似たような動きになるか bashはデフォではオンではないので、zshだろと思うけど 489です ありがとうございます。 とても参考になりました。 コマンドの出力を(だけ)ではなく、シェルそのものの出力(=コマンドの出力もになる)を消すなら if (exec 1>/dev/null;exec 2>&1;ls $f*); then echo $f で始まるファイルがあります fi て現在のシェル環境を変更(元に戻すのが面倒なのでサブシェルでそこの環境を変更)で消すというのもできたな >if (exec 1>/dev/null;exec 2>&1;ls $f*); then execのディスクリプタ操作は羅列ができるようなのね if (exec 1>/dev/null 2>&1;ls $f*); then の方が良さげか >>489 check() { set -- "$1"* [ -e "$1" ] } 最短だとこうかな? set -- "$1"* でシェルのglob展開を用いて位置パラメーターにセットする ファイルが見つかった場合、そのファイル名が$1に入る ファイルが見つからなかった場合、"$1"*という文字列が入る まずありえないとは思うけど"$1*"という名前にアスタリスクが含まれた ファイルがある可能性を考えると>>492 よりも-eでチェックした方が良い と>>494 で書いてあったかw >>493 > >>489 のls使ってる方が見た目なにしたいのかわかりやすいと思うけど ls $f* は意味がない。シェルのglob展開されてからlsを実行してる。 つまりls file1 file2 file3 のようなものを実行してるだけ。 呼び出す前にすでにファイル一覧を取得してる 単に呼び出しコストが高い[ -e ] になってる 見た目っ言ってるだろ そんなコスト気にする必要もないから、見た目とそっちの方を重視してだよ 他人の提案を直接ダメ出しして自分の知識自慢をしたがり、 マウント取るのが目的なやつは他のシェルスクリプトスレでも居るけど、 同じやつかな lsの見た目の何がいいの? ファイルリストを取得しても何やってるのか意味わからんでしょ >>503 > 同じやつかな 違うけど、お前が知識不足でマウント取られたやつだってのはよくわかったよw lsはファイルがあるか確認するのに普通に使ってるだろ、手打ちで >>505 見た目って言ってる裏を読めないで決めつけられてもな 同じやつとしか思えないその短絡的なレス でたw 自分が説明できてないだけなのに 裏が読めてないと相手のせいにする 詐欺師の手段と同じ 自分にある意味ダメ出しされたらイキリマ来るくせに。変なやつ 説明できないとか似たようなフレーズはあいつもすぐにしてたなあ 巣に帰れよw 「裏を読めない」と言った時点で 自分で書いてないって言ってるのってわかってないのかな? 思い込み激しすぎるんだよな 例のPOSIX原理主義者みたいだw 読めませんでしたと素直に言えよ わざわざ見た目って言ってるのはなんなのかは、細かいこと言うなら、 また、そこまで食い下がるならそれぐらい裏読めよ せめて、読めませんでしたと素直になれよ。他人にダメ出しばっかしてないで 自分にダメ出しされたらイキリまくるくせに、他人にダメ出しはするって、 マジでマウント取るのが目的でしかないだろう マウント取るためだから素直には人の言うことは読めないから、 イキリまくることになるんだろうなと そのしつこさはやはりなっていう マウント取るためだからしつこく食い下がるんだろうなあ... 書いてないものは読めません って短絡的に言えちゃうのは確かにアホだな、それが攻撃的な人格のヤツがなら >>513 自らアホ晒してるだけだぞ なんでPOSIX原理主義者に結びつけるのか意味わからん もちろんあんな自ら手足縛るのは嫌いだ/必要ないし、イキってる姿勢はもっと嫌いだし ホント短絡的だな。トンチンカンな決めつけばかりって何したいんだか >>515 > なんでPOSIX原理主義者に結びつけるのか意味わからん そりゃPOSIX原理主義者に知識不足でマウント取られた恨みがあるから、というぐらいは読めるよねえ >>518 イミフすぎな文で、読めないぞ 誰がPOSIX原理主義者なの? 裏読めないやつがPOSIX原理主義者ってことになる文だと思うけど、その文は POSIX原理主義者って出てきたのは、>>510 だぞ >>510 がPOSIX原理主義者?>>510 のレスの相手であろう俺がPOSIX原理主義者?? 俺がPOSIX原理主義者だとしたいなら、 POSIX原理主義者のくせに知識不足でマウント取られた恨みがあるから かな だとしてもPOSIX原理主義者に結びつける説明にはなってないなあ カオスだな。ここまでにしとこか >>520 × POSIX原理主義者 ○ 例のPOSIX原理主義者 シェルスクリプトスレでは、意味が全然変わる。w >>520 510には「POSIX原理主義者」に知識不足でマウント取られた過去があって 恨みがあるから「POSIX原理主義者」という言葉を持ち出した ってことでしょ 510がマウントとられてぐぬぬとなった時に、510には相手がPOSIX原理主義者のように思えたらしいというだけで 本当にPOSIX原理主義者かどうかさえ不明だし、誰がPOSIX原理主義者かなんてどうでもいい fishについて質問です fish_vi_key_bindingsを入力するとviモードに入りプロンプトの左にモードステイタスが表示されますが、 $XDG_CONFIG_HOME/fish/config.fish にfish_vi_key_bindingsを記入した場合はログイン後すぐにviモードか使えますがモードステイタスが表示されません どうやったら表示出来ますか? を、$XDG_CONFIG_HOME/fish/config.fish に書いてるんじゃないの >>529 どうもありがとうございます それらは書かれていませんが、こう書かれてありましたのでコメントアウトしてみたらモードが表示されるようになりました function hybrid_bindings --description "Vi-style bindings that inherit emacs-style bindings in all modes" for mode in insert default visual fish_default_key_bindings -M $mode end fish_vi_key_bindings --no-erase end set -g fish_key_bindings hybrid_bindings インサートモードの時にjjを押したらノーマルモードに戻りたくてfish_user_key_bindingsに以下のように書いたらまたモードが消えました function fish_user_key_bindings fish_vi_key_bindings bind -M insert -m default jj backward-char force-repaint end 端末では正常な $declare -i w0=180 w1=30 w2=20 w3=50 ; w3=w3+(w0-w1)/10-1 ; echo $w3 ですが、shファイルで使うとなぜかエラーになります。(w? の数値は違います) 予期しないトークン `(' 周辺に構文エラーがあります w3=w3+(w0-w1)/10-1 ですが、分割すると通ります。 w2=(w0-w1)/10 ; w3=w3+w2-1 理由をご存知でしたら教えて下さい。 GNU bash, バージョン 5.0.17(1) >>532 理由はよく分からないけど extglob が on ならエラーにならないね なんかbashの仕様のグダグダなところを踏んだって感じだな。 エスケープされていない生の ( は基本的にwordの途中に出てこないので、 w3+( ときたところでsyntax errorになる。 ところが、shopt -s extglob しておくと、 +(hoge|fuga) みたいなパターンマッチを許すため、 w3+( をエラー扱いできなくなり、全部まとめて数式としてパースしてくれる。 *( も可。しかし、/( と -( は不可。 おとなしく $(( )) を使っておくのが吉。 自分が理解できないからって bashのせいにするのは恥ずかしい行為 grepとかで使える正規表現の「\s」は、manページのどこに書いてますか? 「\b」「\w」は、man 1 grepに書いてあるけど、「\s」は見当たらない。 declare -i n; n="3/2" は通るのに、n="1.5" が通らないのはなぜだろ エラーで出ている通り、 リテラルもintegerしかでintegerでは.(5) というのは数値はあり得ない 数値の一部ではないので算術演算子とみるが、算術演算子としてもそんなのない てとこかな リテラル じゃなく、右辺中 か >>537 manには無さげかな。manには無いがPOSIXのドキュメントには詳しくある ああ、決まり事を規定する団体が規定してるドキュメントでは ユニコードコンソーシアム のがある https://unicode.org/reports/tr18/ これを実装していればだが >>540-542 やっぱり記載漏れかな? 理想としては、man 7 regexくらいに全仕様がまとまっててほしいんだけどな。 個人的には、慣れで「\d」を使ってしまって、よく標準コマンド系でガッカリするんだよね。。。 >>543 他の環境は知らんがGNUのなら仕様はinfoを読めというスタンスだぞ >>544 たしかにinfo grepには「\s」が書いてあるな。 でもinfo bashには書かれてなくて、man 3 regexに回されてるような。 結局はinfoでも解決しなさそうな気がするんだけど、違う? info regexだとlibc関数のことが表示されるし、たとえばman 7 regexに相当するinfoは存在しないんでは? まあ、man7セクションに入るような内容はGNUに関係なさそうだとは思う。 シェルスクリプトの [ -a (AND) と -o (OR) ] は非推奨だかんね https://qiita.com/ko1nksm/items/6201b2ce47f4d6126521 には -a や -o ではなく && と || を使うように書かれています。 否定の場合、 [ $a != $b ] と [ ! $a = $b ] はどちらを使ってもいいのでしょうか? >>547 いいんじゃね? ただ [ "$a" != "$b" ] や [ ! "$a" = "$b" ] ってしないとだめだけど あと ! [ "$a" = "$b" ] でもよさそう 昔のFreeBSDでは [ -n abc -lt 5 ] みたいのが通った記憶 [ gnu 8.30で今試すとextra argument '[' と怒られる 手元のunix magazineコレクション(1997-2000)にもこの用法が述べられてるが、まあ要らん機能だわな シェルスクリプトって息が長いから そういう使うべきじゃないものも残っていて困るね さすがに古すぎる機能は互換性切り捨てた方が良くない? whileの、条件が偽でも一度はループって仕様が不思議 そんな仕様なんて無いし シェルスクリプトに文句言ってるやつの8割は 自分の知らない言語を勉強せずに文句言ってるだけなんだなってわかる do while をシェルスクリプトでどう実現するかって話もWeb上であるけど、 それなんの話ってことになるわな ぐぐっても見つけられないんだけど functionの中のlocal変数に整数属性付与って出来ないのかな? bashの話だとして普通に整数属性付いてるぞ? bash -c 'v=1+2; foo() { local v; declare -i v; v=3+4; echo $v; }; foo; echo $v' 7 1+2 というかdeclareで-gをつけない限り デフォルトでlocalになるだろ? >>556 ありがとうございます。 declare はスクリプトファイルの先頭でしか使ったことがなかったのでループ内(や関数)でも使えるとは知りませんでした。 なるほど、それならデフォルトlocalですね。 >>557 使い方の例を見て学ぶタイプなので^^ 3つの引数を必要とする関数があります。 x=$1 y=$2 ANS=$3の絶対値 $3が正の場合はxを、負の場合はyを増減し、xとyとで算出される結果がANSになった時のxまたはyを返します。 x=a[0] y=a[1]とし、最初に$3の符号で添字を0または1に設定することでループ内での場合分けを減らしたいと思います。 質問:整数配列の宣言はできますか? >>558 内部的にはlocalとかreadonlyとか変数に属性つけるやつは 内部的にはdeclareかtypesetの別名 >>559 昨日、近所の吉野家行ったんです。吉野家。 そしたらなんか人がめちゃくちゃいっぱいで座れないんです。 で、よく見たらなんか垂れ幕下がってて、150円引き、とか書いてあるんです。 もうね、アホかと。馬鹿かと。 お前らな、150円引き如きで普段来てない吉野家に来てんじゃねーよ、ボケが。 150円だよ、150円。 なんか親子連れとかもいるし。一家4人で吉野家か。おめでてーな。 よーしパパ特盛頼んじゃうぞー、とか言ってるの。もう見てらんない。 お前らな、150円やるからその席空けろと。 吉野家ってのはな、もっと殺伐としてるべきなんだよ。 Uの字テーブルの向かいに座った奴といつ喧嘩が始まってもおかしくない、 刺すか刺されるか、そんな雰囲気がいいんじゃねーか。女子供は、すっこんでろ。 で、やっと座れたかと思ったら、隣の奴が、大盛つゆだくで、とか言ってるんです。 そこでまたぶち切れですよ。 あのな、つゆだくなんてきょうび流行んねーんだよ。ボケが。 得意げな顔して何が、つゆだくで、だ。 お前は本当につゆだくを食いたいのかと問いたい。問い詰めたい。小1時間問い詰めたい。 お前、つゆだくって言いたいだけちゃうんかと。 吉野家通の俺から言わせてもらえば今、吉野家通の間での最新流行はやっぱり、 ねぎだく、これだね。 大盛りねぎだくギョク。これが通の頼み方。 ねぎだくってのはねぎが多めに入ってる。そん代わり肉が少なめ。これ。 で、それに大盛りギョク(玉子)。これ最強。 しかしこれを頼むと次から店員にマークされるという危険も伴う、諸刃の剣。 素人にはお薦め出来ない。 まあお前らド素人は、牛鮭定食でも食ってなさいってこった。 答え:できまsん ありがとうございます。 色々やってみたら、配列として宣言しなくても使えるようです。 declare -i i a[0] a[1] ; a[0]=3 ; a[1]=6 ; i=1 ; a[$i]=${a[$i]}+1 ; echo a=${a[$i]} a=7 ちょっとスレチかもですが、 for filename in * とかでカレントディレクトリにあるファイル名を得る場合、どんな順番なのでしょうか? ディレクトリエントリ順とか、ファイル名順とか。 ある程度ファイルがあるところで echo * すればわかる >>563 GLOB POSIXに規定されてる The glob() function shall store the number of matched pathnames into pglob->gl_pathc and a pointer to a list of pointers to pathnames into pglob->gl_pathv. The pathnames shall be in sort order as defined by the current setting of the LC_COLLATE category 名前順 >>566 ,563 SORTしないというオプションもあるが、その場合には順番の決まりなんてないということになるね >>568 > □お約束 > ・特記なき場合はBourne Shell(/bin/sh)もしくはPOSIX準拠の互換シェルがデフォルトです。 ■ このスレッドは過去ログ倉庫に格納されています
read.cgi ver 07.5.1 2024/04/28 Walang Kapalit ★ | Donguri System Team 5ちゃんねる