シェルスクリプト総合 その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/ seq -f 'hoge%02g' 0 99 の間違い。00からなので >>77 >>78 もの凄く高度ですね… 自分には理解できるかわかりませんがじっくり読ませてください ありがとうございます お題として遊ぶなら、findしてexec内でやっつけるとかかな findは存在を確認するのは楽だろうけど、存在しないことを確認するのは面倒じゃない? >>77 [ ! -f "$filehoge" ] && exit 1 の間違いもあった。&&抜けてた、すまん。 >>79 ん?まあ、for(forはアレでアレの回避があったような気がするがすぐ忘れる。 | while read hoge しか使わないので) と if(明示するだけだけど)で書けばいいよ ... for hogedir in $(seq -f 'hoge%02g' 1 99) ... if [ -d "$hogedir" ] && [ ! -f "$hogedir/$filehoge" ]; then cp "$filehoge" "$hogedir" ... fi あー、" で括るだけか。アレの場合も for hogedir in "$(seq -f 'hoge%02g' 1 99)" が、よりかな やっぱりダメなのかな?? touch 'hoge 01';touch 'hoge$02' for name in "$(/bin/ls -1)" /bin/ls -1 | while read name やっぱforはメンドクサイから、安心簡単な while でいいやっ >>82 考えるのに役立つアドバイスありがとうございます >>83 >>84>>85 更新してくださりありがとうございますm(_ _)m 読ませていただきます 初心者ですが面白くなってきました 今日中に仕上げられるよう頑張ります >>82 それはexecの中でやればいいんじゃ お題とは別に、存在しないことの確認だけだったら、 検索条件に入れればいいだけだし 質問です。 シェルスクリプトファイルを実行する方法として 1. 利用者に応じた実行権限を賦与する $ chmod +x scriptfile.sh $ ./scriptfile.sh 2. sh(1)コマンドの引数として実行する $ sh scriptfile.sh という方法がありますが,どちらがより良いか教えてください(というかスクリプトの実行結果自体にはたして違いはあるのでしょうか)。 今まで一つ目の方法しか知りませんでしたが,もし二つ目になんら欠点がなければよりコマンドの数が少ない (極端に言えばchmod(1)コマンドがなくてもできる)後者の方法を使っていきたいです。 どうかよろしくおねがいします。 psで見てみ。1 でも、そのシェルスクリプトファイルのシバン(*1)で指定したインタプリタ(シェル)を、引数としてそのシェルスクリプトファイルをで起動してるから 1はコマンド、2はスクリプトファイルっていう違い。/usr/binなどの中のコマンドでも実態はシェルスクリプトやPerlスクリプト等なのがあるけど、そんなの気にしてない気づいてなくコマンドとして使ってたりするだろ? まあ、コマンドとして必要じゃない(コマンドの数が少ないって意味がわからんが一時的とかか?)んだったら、別にスクリプトファイルとしてで全然普通 1) お約束事項のような #!/bin/sh もう俺は気にしてなくて #!/bin/bash だけど >>82 hogefile="test" find . -maxdepth 1 -type d -name 'hoge[0-9][0-9]' -exec bash -c "test -f {}/$hogefile || cp $hogefile {}" \; こんな感じとか?俺は、俺も、そうはしないけど。-exec は使ったことないのでどこまでできるのかよくわからんな。なのでbashスクリプトにした/逃げた >>91 ありがとうございます。 ps(1)コマンドで確認したところ,たしかに両方ともにシェルが始めに起動されていました。 (素朴な疑問なんですが,PIDが連続しているのは偶然ですか? 原理的に必然ですか?) 1の方法だと一見シェルは起動されていないように見えるけれども,シバンに書かれたシェルがまず起動するということですね。 ということは全く違いはないという理解でよいでしょうか。 >>92 なるほど。1の方法は永続的,2の方法は試験目的で一時的に作ったファイルなどに対し用いるということですね。 シェルプロセスが勝手に起動されるか明示的に起動するかで、なんかあった(rcやprofileを読まないとか起動時の環境設定の動作)が今回のようなのは関係ないだろう、気にすんなw PIDはだいたい普通にインクリメント。なにかプロセスが起動するごとにそれの新しいPIDはインクリメントされた値かな OSによってはセキュリティ的な理由でPIDをある程度ランダムに割り当てるので連続にはならない。 BSD系はどれもデフォルトだとランダムじゃないかな。 PIDが若いから特権があるわけでもないしPIDが推測しやすいからっていうセキュリティ懸念ってなんだろ? cat >/tmp/tmpfile.$$ みたいに手抜きな一時ファイル作成してると シンボリックリンク攻撃くらうからそのリスクを減らせたりする。 ちゃんと攻撃避ける正しい書き方してれば関係ない話だけど、 世の中にテキトーなスクリプトは尽きないから。 なるほど。OSのセキュリティではなくPIDを利用したナニかに対するか ん?PIDを知ることができる(当然知ることは普通にできる)ってとこがキモで推測しやすいのとは別のような。まあ、いいや、ナニかあるなってことで ああ、シンボリックリンク攻撃を誤解してた。事前に(大量に)シンボリックリンク作ってしまうわけね。なるほど 知り合いから教えてもらったパソコン一台でお金持ちになれるやり方 時間がある方はみてもいいかもしれません グーグルで検索するといいかも『ネットで稼ぐ方法 モニアレフヌノ』 GXGZT シンボリック攻撃ってシンボリックリンクを作成する時にパーミッション関連の隙を突いて本来保護されているコマンドを改竄することだよね。 大量に作成する必要なないんじゃないかしらん。もちろんある種の陽動にはなるだろうけど。 >>77 >>78 これで一発で成功しました 驚いています このコードをもっと理解すると共に、自分も先輩のようなプログラマーになれるよう勉強を続けていきたいです マジで助かり、勉強になりました 本当にありがとうございました もちろん>>83 の修正も加えさせていただきました コードをくだすった方と同じ方かはわかりませんがそもそも>>75 でこちらの仕様を把握してくださったのがすごい 要求仕様、要件定義の大切さも少しわかりました そしてコードはこちらの望む通りの結果を出して一発で動きましたよと >>105 別人だ。俺はスマホだからここにコードは書けん >>106 そうでしたかm(_ _)m いずれにせよスレの複数の先輩方にお世話になりました しかも勉強になります あのなぁ、お前さんここをどこの板だと思っているんだい? 歴史あんだぜ まあその話はもうほんとに一昔前の出来事になっちまったけどな なんだったか、2chの鯖に関する貢献があったような 当時からいたわけじゃないからどっかのサイトで知った話だが Flash黄金期にその話がFlash化されてたから見て知ったな read.cgiの改良作業だよね。 直接関わってはいないけど、当時はリアルタイムで見ていたし、手元の どこかに運営から住民に開示されたread.cgiも残ってると思う。 アクセスが増えて通信量が増加して、当時借りてたホスティング業者から 追い出されそうになってたんだけど、HTTPの通信をgzipで圧縮して通信量を 削減しようという話だったかと思う。 ただ、UNIX板でも話をして作業には参加していたものの、プログラム板と かの方でもガリガリやっていたような記憶がある。 それとは別に SYN flood 攻撃に対し SYN cookie 有効化で対抗した時はUNIX板で主に議論してた気がする。 リアルタイムで見てたというか発言してたけど(SYN cacheと比較した得失とか書いた気が)、 こういうのはあくまで個人としての行動なので板自慢に繋げるのは好きじゃないな。 むしろ統一とかとれてなくてカオスなのが5chの良いところだと思うので。 >>112 gzip圧縮ってapacheの設定じゃないの? 他の顧客がいるからミドルウェアで圧縮できない、というホスティング屋を使っていたんじゃなかったのかな(後から知った話だから、違うかもしれない) なれ合いですらなくて、おっさんが勝手に郷愁に浸ってるだけという。 $ cat a.file > b.file とやるのと $ cp a.file b.file とやるので違いが生じる場合はありますか? >>120 b.fileというディレクトリがあった場合の動作 >>123 によると cat a.file > b.file/ ってやるといいんだって 意図してディレクトリじゃないからつけろもなんもないのにな Linuxのは実装はしてるみたいだな。デフォではないから話の流れでの実装してるとは言えんけど シェルスクリプトの勉強をするのにおすすめの本はありますか? お知恵お借りしたいです。 awk '($3 !~ /ここにパイプ区切りで記述したい/) && ($4 ~ /01/)' output.txt 上記のawkで条件に当てはまるファイルを絞り込みたいのですが その1 別ファイルからのawkの結果を $aaa に設定してある その2 $aaa は複数列の出力なので set コマンドにて位置パラメータに分けてある その3 各変数を展開して文字列としてパイプで区切ってawkを使いたい。 以上のようなことをやってみたのですがどうもうまく行きません。 また、違うやり方もあるようでしたらご教示いただけるとありがたいです。 よろしくお願いします。 > $aaa は複数列の出力なので set コマンドにて位置パラメータに分けてある これはどういう意味? set はシェル自身の設定だと思うんだけども cat ZZZ.txt |grep XXX hoge fuga と複数行でしたので aaa=$(cat ZZZ.txt |grep XXX) としてみました。 そして set $aaa と設定して $1 $2 $3 ...と変数が自動で割り振られるなら増減しても対応できるのでは考えました。 (本来は0個のときもあるのでそれも考慮しなければならないんですが) そして $1 等に入っている変数(hogeやfuga) を展開してパイプで区切れれば動くと思うんです。 ごめん俺の理解が悪いと思うのだがあなたのやりたいことが見えない。 他の人にまかせるわ。 もしくはZZZ.txtの内容をプライバシーに障らない程度に具体的に教えてほしい。 「ZZZ.txtからgrepで取り出した値をパイプで連結して処理する」という文言からは ZZZ.txtには命令が一行ずつ書かれているように受け取れるのだが、そうじゃないよね。 それとも「パイプで繋ぐ」というのはシェルのパイプ実行ではなく単に文字列としてパイプを区切りとして使うという意味? もしそうなら $ cat ZZZ.txt | grep XXX | tr '\n' '|' | sed 's/|$//1' ↑こういうので行けるけど。違うでしょ? 説明がヘタですみません。ZZZ.txtの中身はyoutube等の URL タイトル 日付 がタブ区切りで複数行書かれているファイルです。 123.com hoge 02 456.com fuga 05 789.com peke 08 のような感じです。 それらから条件から当てはまる行や列を抜き出してパイプ区切りにしたいのです。 パイプの解釈は hoge|fuga で hoge or fuga と展開して awkのパターン入れて読ませたい訳です。 >>137 なるほどね。こういうこと? (ZZZ.txtの代わりにヒアドキュメント使ってる) $ cat <<. | awk '($2 ~ /(hoge|fuga)/) && ($3 ~ /02/) {print}' example111.com hoge 02 example222.com hoge 03 456.com fuga 05 456example.com fuga 02 789.com peke 08 . example111.com hoge 02 456example.com fuga 02 勉強不足でヒアドキュメントの知識が浅くて申し訳ないのですが 多分合ってると思います。 うまくいかないのは hoge|fuga の部分が一定でなく peke|hoge|miso だったり fuga のみだったりするので悩ましいのです。 条件をコマンドの結果から作りたい&その条件をawkの条件に埋め込みたいってだけ? hogehuga=( $(cat ZZZ.txt |grep XXX) ) SAVEIFS=$IFS IFS=$'|' hogehuga="${hogehuga[*]}" IFS=$SAVEIFS [ "$hogehuga" = "" ] && hogehuga="0個の条件" awk '($3 !~ /'"$hogehuga"'/) && ($4 ~ /01/)' output.txt って感じとか ああ、条件の作成は>>136 の最後ですでにワンライナーで教えているのか。しつれい >>139 そのhoge|fugaはどこから来るの? grep(1)コマンドの結果? >>135 の最初で説明してね?>>135-137 は噛み合ってないだけかなw というか、>>136 の確認/質問のキモがわかってないというか 条件文の | をパイプとかいうからわけわかんなくなる そういう場合はパイプって言わないんですか。失礼しました。 正規表現でつかう or の役割を hoge fuga の間には挟みたいのです。 >>145 >>136 >$ cat ZZZ.txt | grep XXX | tr '\n' '|' | sed 's/|$//1' >↑こういうので行けるけど。違うでしょ? って教えてくれてるやん。「違わない」「それです」でいいんじゃないの?それが違うならどう違うって言うべきかと(どうみても違わないとしか思えないけど) 質問自体がアレだが自分の言いたいことをうまく説明できないのはいいとして、応えてくれてる人の言ってることがわからない/それに応えないのはアレだな awkの手前で別途 fgrep -f か egrep -f を使った方が、改行→「|」変換をサボれて楽な気がする。 fgrep/egrep -f を使うときは bashないし zsh 依存になるけど fgrep -f <(grep XXX ZZZ.txt) と書くともっと楽だね。 \じゃないよバックスラッシュだよ というのがありそうな気もしないでもない シェルスクリプト内で自動で行いたい旨を 書き損じておりました。 cat ZZZ.txt |grep XXX hoge fuga から awk '($3 !~ /hoge|fuga|neko/) && ($4 ~ /01/)' output.txt としたいのです。 >>146 >$ cat ZZZ.txt | grep XXX | tr '\n' '|' | sed 's/|$//1' でまさしく狙い通りの出力がされるのですが>>133 のawkのパターン部にどうかけば同じ文字列が出せるかわかりません awk の文はただの文字列でしかない awk '($3 !~ /'"$aaa"'/) && ($4 ~ /01/)' output.txt でも、 awk "(\$3 !~ /${aaa}/) && (\$4 ~ /01/)" output.txt でも(他にエスケープ必要なのあるかな?)、 普通にシェル変数を(文字列内に)展開するのと変わらんぞ 書き損じどうこうじゃなくて、受け応えができないのが致命的ではあるなw よく見たら、 hoge fuga から hoge|fuga|neko って、nekoはどこから来たっていう。まあうっかりだろけど みなさん申し訳ありません >>150 のレスを見てクォートをよ〜く見なおしたら動きました。 初心者のたわごとに付きあわせてしまい申し訳ありませんでした。 sedコマンドでSGRを扱いたいんですがどうすればいいですか。 $ echo abc | sed 's/^a/\033[1m&\033[0m/1' などとしてaを太字にしたりしたいです。 echo abc | sed -e 's/^a/'$'\033[1m&'$'\033[0m/1' 横からだが、 なんのこっちゃと思ったら $'' はエスケープ文字処理してくれんのね。なるほど 最初のだけでいいのでは?もしくは最初に付ける。もしくは逐一付けて閉じる echo abc | sed -e 's/^a/'$'\033[1m&\033[0m/1' echo abc | sed -e $'s/^a/\033[1m&\033[0m/1' echo abc | sed -e 's/^a/'$'\033''[1m&'$'\033''[0m/1' と思いました ありがとうございます。解決しました。 これは後出しになってしまいますが、POSIXの範囲でやりたかったので $''ではなく$(printf)を使いました。 英語圏の序数詞を適切に処理するシェルスクリプト(というかワンライナー)を考えたのですが添削してください $ for i in $(seq 15); do echo $i$(case $i in *1) echo st;; *2) echo nd;; *3) echo rd;; *) echo th;; esac); done 出力は一応望み通りでまたPOSIX utils+seq(1)のみで実行可能です。 11st とか 12nd になってるけどそれはいいの? すいません。>>161 さまのおっしゃる通りです。 $ for i in $(seq 30); do echo $i$(case $i in *1?) echo th;; *1) echo st;; *2) echo nd;; *3) echo rd;; *) echo th;; esac); done これでどうでしょうか まず添削してくださいってどうしてほしいんだ ちゃんと動いてんならそれはもう正解だと思うんだが >>167 ちゃんと動いているかどうか判断できないから聞いてるんでは エラるのはbashのバージョンのせいかな?3.2.57ではエラる/4.3.48では問題ない だとしたらPOSIX utils云々はちょっと違うんじゃねと思わなくもない。POSIX utils云々って書いている意図がよくわからんけど case文をこうしたら3.2.57で動いた case $i in (*1?) echo th;; (*1) echo st;; (*2) echo nd;; (*3) echo rd;; (*) echo th;; esac おおっ。ぱーふぇくつ(?)やねっ! ( が必要??なんなんなん??と謎だけど $() 内では、case の ) を case の ) と認識してないで、$( の終わりと見てまうってのか。それで普通は使わない ( をか。いちおう ( はつけてもいいのね。つけてもつけなくてもいい存在みたいだけど え…… >>164 のやつ、GNU bash 4.4.12,zsh 5.3.1,dash全てで動いたんだけど(Debian GNU/Linux)。 もちろん$()判定の不具合を回避したcase ()版でも動いたけれども。 bashの前のバージョン 3.2.57 でのなんですけど あ。>>170 でそう書いてあるな……。すいません。 sedなどで 1. 「%」以降改行までを削除 2. ただし「%」の直前に「\」があれば削除しない (要するにTeXシステムのコメント除去) をしたいです。また、できればなのですがPOSIXの範疇で行いたいです。 しかし2.を表わす正規表現が分かりません。教えていただけないでしょうか。 sedでsed -e '/%/{}'のようにして{}の内部で「\」が前置されているか判定するのが一番一般的かとは思うのですが それさえ……。 どうかよろしくおねがいします。 ■ このスレッドは過去ログ倉庫に格納されています
read.cgi ver 07.5.4 2024/05/19 Walang Kapalit ★ | Donguri System Team 5ちゃんねる