シェルスクリプト総合 その28

1名無しさん@お腹いっぱい。2018/08/02(木) 05:22:16.82
シェルスクリプトの総合スレです。
□お約束
・特記なき場合は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/

52名無しさん@お腹いっぱい。2018/09/11(火) 17:42:07.09
>>51
ム板の本スレは意図的に荒らしてて(だからバレてもOK)、
前スレは天然で荒らしてる面がある(だからバレたくない)
って程度の違いはありそうだね。

53名無しさん@お腹いっぱい。2018/09/12(水) 04:28:30.52
>>52
いやいや、単に荒らしは最初から隠すつもりもなく、
バレようがバレまいが関係ないんだよ。

荒らしにとってはは最初から隠してるわけでもないが、
でもこのスレの住民がその荒らしのIDを見たくて移動したんでしょ?
それでんで、見て何がしたかったのか不明だけどなw

IDが出ていれば荒らされないとでも思った?

54名無しさん@お腹いっぱい。2018/09/12(水) 08:39:27.35
>>53
荒らしさん、こんにちはー

55名無しさん@お腹いっぱい。2018/09/12(水) 13:03:52.35
>>54
はい、こんにちは。
やっと気づいた?w

56名無しさん@お腹いっぱい。2018/09/12(水) 13:57:49.01
IDを何に使うかなんて自明でしょ。
まさか分からないってことはないよな?

57名無しさん@お腹いっぱい。2018/09/13(木) 04:39:22.11
荒らしをNGIDにして見えなくするため、という説がある

確かにNGIDにすると見えなくなるが、
荒らしの書き込みを止めることはできない

荒らしはどんどん自分の意見を書き込むが
それに対しての反論はできない。
なぜなら荒らしの書き込みが見えないから

荒らしとNGIDに入れてない人とのやり取りでスレは埋まっていく
はたから見れば、話についてこれず時々レスするが
荒らしに論破され何も言い返せない構図のできあがり
それ全体の荒らしの濃度が高まる

そしてIDは変わるから毎日の登録作業が増える。
忘れるとついレスをしてしまう

58名無しさん@お腹いっぱい。2018/09/13(木) 09:15:51.30
というわけで、以下のどっちかの運用にするのがよくあるパターンだな。
・このIDは昔から粘着してる奴だから無視するぜってコメントを時々入れつつ無視する
・奇特な人物がいちいち反論するので、スレにいる他のメンバーは、連鎖アボーン設定して安心してその議論全体を無視する

IDがないとこういう回避ができないから、ひたすら我慢することになる。

59名無しさん@お腹いっぱい。2018/09/13(木) 15:25:23.10
連鎖あぼーんって荒らしが誰だれかれ構わずレスしたら
みんな消えちゃうの?

60名無しさん@お腹いっぱい。2018/09/13(木) 15:40:35.15
それを荒らしにわざわざ教えてやる理由はないな。

61名無しさん@お腹いっぱい。2018/09/13(木) 15:45:05.41
お前が荒らしだろ

62名無しさん@お腹いっぱい。2018/09/13(木) 15:45:42.12
バレたかw

63名無しさん@お腹いっぱい。2018/09/13(木) 15:46:13.40
まあ回線切ってIPアドレスを変えればいいだけだしな

64名無しさん@お腹いっぱい。2018/09/13(木) 20:00:10.94
>>59
やってみればいいんじゃね?

65名無しさん@お腹いっぱい。2018/09/13(木) 21:16:50.93
つまりIDやIPアドレスを変えてNG避けする意志のある荒らしってことだから、
IPアドレスも表示させるようにして、
IPアドレスの範囲を使ってNG登録するのもやむなしってことだな。

今でも2つのプロバイダーを使い分けて自演してるって
自分でバラしてたから、NG登録する範囲も2通りは必要だと。

66名無しさん@お腹いっぱい。2018/09/15(土) 09:20:57.31
特定文字列の除外リストを元に除外処理をしたいんだけど
リストとかあきらめてgrepをフィルタファイルとして別するのが一番楽?
やりたいのは以下のようなことなんだけど
シェルスクリプトなのにプログラミング的なことやって
grepのフィルタを組み立てることに違和感を感じてる(面倒とはっきり言えって?)

echo ${DATA_REC} | grep -e AAA -e BBB -e CCC

if [ $? -eq 0 ]
then
continue
fi

# 継続処理

67名無しさん@お腹いっぱい。2018/09/15(土) 09:24:06.05
> grepをフィルタファイルとして別するのが一番楽?

ってのはファイルにgrepのコマンドを書いてreadで読んで
echo ${DATA_REC} ${grep_cmd}
とかにするってことね
grepコマンドが書かれてたら適用
書かれてなかったらスルーって感じ

68名無しさん@お腹いっぱい。2018/09/15(土) 09:26:44.49
ああパイプがうまくいかないから若干判定が必要か・・・

pi@melchior /tmp $ export grep_cmd=" | grep -e AA -e BB"
pi@melchior /tmp $ echo AAA $grep_cmd
AAA | grep -e AA -e BB
pi@melchior /tmp $ echo AAA | $grep_cmd
-bash: |: command not found
pi@melchior /tmp $ export grep_cmd=" grep -e AA -e BB"
pi@melchior /tmp $ echo AAA | $grep_cmd
AAA
pi@melchior /tmp $

69名無しさん@お腹いっぱい。2018/09/15(土) 10:04:14.90
もうベタで書いてしまった・・・
でも順調!すげーよく動いてる!

この件は今後の課題にしよう

70名無しさん@お腹いっぱい。2018/09/15(土) 11:49:54.77
除外する文字列をファイルに入れて
grep -f か grep -v -f でいいような気がする

71名無しさん@お腹いっぱい。2018/09/15(土) 12:13:24.53
>>66
> シェルスクリプトなのにプログラミング的なことやって

シェル芸じゃなくてスクリプトなんだから
プログラミングで当たり前だよw

72712018/09/15(土) 12:37:34.28
>>67
少し考えてみたが、俺もgrepの-fオプションを利用するのが一番楽だと思うな
ただ昔、除外リストの否定とかやりたかったんで書いたことはあるが

73712018/09/15(土) 12:43:55.58
grep -f 使えばいいから不要だが
お手軽に>>66のようなことをするのならこうかな
リストにスペースなどが入っていたらうまくいかんがw
文字列の組み立ての参考として

echo ${DATA_REC} | grep $(printf ' -e %s' $(cat list))

74名無しさん@お腹いっぱい。2018/09/22(土) 07:11:59.06
シェルスクリプトじゃなくてシェルの基礎を訊いてアレだけど
bashの$()と``って使い分けた方がいいの?
端末ではバッククォート多用してるけども

75名無しさん@お腹いっぱい。2018/09/22(土) 09:23:42.74
``は古い書き方。ネストができないという欠点が有る
bashに限らず、$()を使ったほうが良い。欠点は文字が一文字多くなるだけ

76名無しさん@お腹いっぱい。2018/09/22(土) 10:20:58.39
きっちりエスケープすればネストはできるよ。もちろん推奨はせんが

77名無しさん@お腹いっぱい。2018/10/07(日) 11:42:06.75

78名無しさん@お腹いっぱい。2018/10/13(土) 19:33:57.01

79名無しさん@お腹いっぱい。2018/11/09(金) 16:05:12.56
test $(date +%w) -eq 5

今日が金曜日なら5が出るんですが、-eq というのはコマンドなのかtestコマンドのオプションなのか、これは何ですか?

80名無しさん@お腹いっぱい。2018/11/09(金) 16:08:05.57
自己レス
-eq はtestコマンドのオプションで、==の事みたいですね

81名無しさん@お腹いっぱい。2018/11/09(金) 16:09:52.77
test コマンドのオプションです。

ところで今日は金曜日ですが5は出ませんよね。
戻り値は0となりますが……何か勘違いしている気がします。

82名無しさん@お腹いっぱい。2018/11/09(金) 16:18:31.36
すみません

test $(date +%w) -eq 5 && echo "今日は金曜日!"

これだと、金曜日だとechoが実行されました

83名無しさん@お腹いっぱい。2018/11/09(金) 16:20:38.51
>>82
自己レス
金曜日かどうか調べて金曜日なら戻り値は0、
で、戻り値が0の場合echoが実行されるって事ですね

84名無しさん@お腹いっぱい。2018/11/09(金) 16:32:51.67
毎月第2月曜日と毎月第2週の月曜日とでは、指す日にちってもしかして異なります?

0 17 8-14 * test $(date +%w) -eq 5 && command
こんな風にcronで毎月第2金曜日とか指定したいんですが、

例えば今月の5日で言うと、5日は1回目の月曜日だけど、月の2週目にあるので疑問に思いました。

0 17 8-14 * test $(date +%w) -eq 1 && command
これだと今週の月曜日には実行するされないですよね?

85名無しさん@お腹いっぱい。2018/11/10(土) 02:31:24.55
読みづらい。testなんて使うな

[ $(date +%w) -eq 5 ] && echo "今日は金曜日!"

86名無しさん@お腹いっぱい。2018/11/10(土) 10:01:16.06
>>85
[ ]ってなんですか?
ググろうにも記号なのでググれないです

87名無しさん@お腹いっぱい。2018/11/10(土) 10:12:06.10
man [

88名無しさん@お腹いっぱい。2018/11/10(土) 18:00:25.18
bash(バージョン 4.4.12(1)-release)でスクリプト書いててちょっと謎が

$ a=1; b=2; [[ ${a}<=${b} ]]; echo $?
こうするとちゃんと終了コードの0が返ってきますが

$ a=1; b=2; [[ ${a} <= ${b} ]]; echo $?
比較演算子の前後にスペースを入れると「条件式に構文エラーがあります」「`${b}' 周辺に構文エラーがあります」と怒られます

$ a=1; b=2; [[ ${a} < ${b} ]]; echo $?
比較演算子をleでなくltにするとまた0が返ります

これって何故なんでしょう?

89名無しさん@お腹いっぱい。2018/11/10(土) 19:37:33.60
>>88
[[ ... ]] で使える演算子に <= は存在しない

それは数の比較ではなく
[[ "1" < "=2" ]]
という文字列の比較になっている

なので <= の右に空白を置くと
[[ "1" < "=" "2" ]]
となりエラー

条件式
https://linuxjm.osdn.jp/html/GNU_bash/man1/bash.1.html#lbBW

90882018/11/10(土) 21:37:24.33
>>89
さっそくありがとうございます
そうか、イコールをつけない不等号で上手く動いてるように見えるのは、文字列として辞書順で比較してるからなんですね
どうやら私の頭の中では、二重丸括弧での算術式展開とゴッチャになってたみたいです
何時間も唸ってたのが一撃でスッキリしました。ありがとうございました

91名無しさん@お腹いっぱい。2018/11/10(土) 21:45:21.63
記号のコマンドってドットと[以外にもあるんか?

92名無しさん@お腹いっぱい。2018/11/10(土) 22:29:10.53
>>91
:

93名無しさん@お腹いっぱい。2018/11/11(日) 00:38:12.80
>>87
もしかしてtestと[]はだいたい同じですか?
testを使わない方がいいのはなぜなんでしょうか?

94名無しさん@お腹いっぱい。2018/11/11(日) 19:15:20.55

95名無しさん@お腹いっぱい。2018/11/11(日) 23:47:57.65
>>87
それで出てくるのは /usr/bin[ の方のmanじゃないだろうか

96名無しさん@お腹いっぱい。2018/11/15(木) 14:21:20.04
bash の場合。

$ type [
[ is a shell builtin

$ help [
[: [ arg... ]
Evaluate conditional expression.

This is a synonym for the "test" builtin, but the last argument must
be a literal `]', to match the opening `['.

97名無しさん@お腹いっぱい。2018/11/21(水) 22:42:24.51
sedで\1を変数名としていっぺんに異なる部分を異なる変数の内容で変換できませんか?

sed -e "s/<\(.*\)>/${\1}/g"
こんなかんじの

98名無しさん@お腹いっぱい。2018/11/29(木) 16:58:28.90
#!/bin/bash
# 変数URL, ETAGには既に適切な値が入ってるとする
OPT=('--header' "'If-None-Match: ${ETAG}'")
curl "${OPT[@]}" "${URL}"

こんなスクリプトを書いたけど、curlと鯖のやりとりを覗くと、リクエストヘッダのIf-None-Matchの行にシングルクォーテーションが付いて

'If-None-Match: (ETAGの値)'

と送られてしまう。で、試しにcurlの行を

echo "curl ${OPT[@]} ${URL}" > /tmp/tempfile
. /tmp/tempfile

と書き換えて実行すると、ちゃんと正常に動く。man bashを読んだりbashの引用符の扱われ方をググってみたりしても、何が何だかさっぱり分からない。
どなたか助けてくれませんか。

99名無しさん@お腹いっぱい。2018/11/29(木) 18:06:56.14
自己レス
curlだからとか関係ないな。変数にシングルクォートで囲ったものが入ってて、それをダブルクォートで囲った配列展開してるんだから、そのパラメーターはそのままシングルクォートつきになって当然。
しかし、ETAGはダブルクオートを含むしhttpリクエストヘッダはスペースを含むから、全体をシングルクォートで囲まなきゃならんのだよな。
やっぱどのタイミングでどのクォートがどう展開されるのか、一段階ずつ追いかけてみるしかないのかな

100名無しさん@お腹いっぱい。2018/11/29(木) 21:56:13.42
なんか混乱しとるなw
まあ、ダブルクォートは、他言語を使っている人からすれば
直感に反する機能だってことに、俺も最近気づいたんだけどな
ただどこがどう違うかを言葉で説明したことがわけじゃない。やってるみるか?

・シェルスクリプトは文字列として展開されて実行されているようでそうではない
・ダブルクォートは文字列を囲う機能ではなく、変数展開の挙動を変えるエスケープの一種
この二つに集約されるかなぁ

> しかし、ETAGはダブルクオートを含むし
これ関係ないんだわ

OPT=('--header' "If-None-Match: ${ETAG}")
だと
OPT=('--header' "If-None-Match: "686897696a7c876b7e"")
こうなってしまい
OPT=('--header'   "If-None-Match: "  686897696a7c876b7e  "")
のように解釈されると思ってしまうが違う。
別に文字列展開されてから、動くわけじゃない

ダブルクォートは「 If-None-Match: ${ETAG} 」の部分を一つの引数として
扱いますよー(ただし中の変数は展開されますよ)という意味。
変数の中にダブルクォートが入っていようが改行が入っていようが関係ない

またダブルクォートはそれだけの機能ではなく $@ が入っている場合に異なる挙動をする
"$@" が入っている場合、一つの引数ではなく複数の引数として扱われる
例えば引数$1〜$5が存在する場合、"$@" は "$1" "$2" "$3" "$4" "$5" と等価
また"foo$@bar" となっていた場合、 "foo$1" "$2" "$3" "$4" "$5bar" と等価
引数が一つなら "foo$1bar" だし、引数がゼロの場合は、書かなかったのと同じとなる("" 空文字にはならない)

このように文字列として囲う機能じゃなくて、中に入ってる文字や変数の解釈の仕方に影響を与える機能

101名無しさん@お腹いっぱい。2018/11/29(木) 22:00:40.89
ちなみに "$@" を複数の引数に展開されたくなければ "$*" を使う

102名無しさん@お腹いっぱい。2018/11/30(金) 06:16:21.18
>>100-101
ありがとう。おかげで、サクッと片付きました。素直に

OPT=('--header' "If-None-Match: ${ETAG}")
curl "${OPT[@]}" "${URL}"

で何の問題もなく動作しました。最初にcurlについて調べてたときにETAGを使う例でシングルクォートが使われてたのに、ずっと脳味噌が引っ張られてたようです。
上の行で変数に入れる時点で、スペースを含む一つの文字列として扱われてるんだから、あとはその中身がなんであるかに関係なく、"$[@]"で展開すればいいわけですね。

ありがとうございました。

新着レスの表示
レスを投稿する