シェルスクリプト総合 その9
レス数が900を超えています。1000を超えると表示できなくなるよ。
0001名無しさん@お腹いっぱい。
2007/08/15(水) 07:25:02スクリプトのお勉強・自慢・腕試しなどにどうぞ。
まずは注意点、リンク、地鎮祭など(>>1-6くらい)をご覧ください。
□お約束
・特記なき場合はBourne Shell(/bin/sh)がデフォルトです。
bash/zsh/ksh/ashなどに依存する場合は明示しましょう。
Linuxユーザは/bin/shの正体がbashなので特に注意。
・csh/tcshのシェルスクリプトは推奨されません。
(理由は「csh-whynot」でググれ)
・UNIXにはシェルスクリプトに便利な小さなコマンドがいろいろあります。
manや参考リンクを見ましょう。
aproposないしはman -kでそれらしい単語による簡単な検索もできます。
・シェルスクリプトのことをシェルってゆーな
・シェルで使えるワイルドカード等は正規表現ではありません。
正規表現の話題はスレ違い(正規表現スレへ)
□初心者へのアドバイス:
・適した道具を判断するのも頭の重要な使い方。シェルスクリプトよりも
RubyやPerlの方が適した仕事には素直にそちらを使いましょう。
・知らないコマンドが出てきたらmanを引きましょう。
・思い通りに動かないときは、まずは sh -x でトレースしましょう。
前スレ
シェルスクリプト総合 その8
http://pc11.2ch.net/test/read.cgi/unix/1171517324/
0820名無しさん@お腹いっぱい。
2008/02/02(土) 12:44:48$ ash
$ set -u
$ echo $#
0
$ echo "$@"
$
問題なしw
0821名無しさん@お腹いっぱい。
2008/02/02(土) 12:54:11FreeBSD orz 8.0-CURRENT FreeBSD 8.0-CURRENT #1: Tue Jan 29 01:35:03 JST 2008 root@:/usr/obj/src/sys/orz i386
$ sh
$ set -u
$ echo $#
0
$ echo "$@"
@: parameter not set
実例が提示されたので、以下は嘘。
> ${1+"$@"}が必要なようなシェルは今は残っていない。
0822名無しさん@お腹いっぱい。
2008/02/02(土) 12:59:31だから、set -u の話は後出し
> ${1+"$@"}が必要なようなシェルは今は残っていない。
のは、"$@" が "" (空文字列) に展開されるような古いシェルのこと。
よって、
> ${1+"$@"}が必要なようなシェルは今は残っていない。
は、正しい。
0823名無しさん@お腹いっぱい。
2008/02/02(土) 13:06:51ハイハイ、後出し。wwww
> ${1+"$@"}が必要なようなシェルは今は残っていない。
これは嘘。
0824名無しさん@お腹いっぱい。
2008/02/02(土) 13:14:38${1+"$@"}が必要な理由として、
set -- -l と FILE="foo bat.txt" と、set ${1+"$@"} が
別々のモジュールになるかも知れないので、
と言っている。
これは、引数が0個になる場合があるから、と言う意味に他ならない。
それに対する反論として、
>>813 で、${1+"$@"} は不要と言っている。
その「後」で、>>814 が set -u の話を持ち出している。
よって、>>814 の set -u が後出し。
あと、未だに set -u で "$@" がエラーになる FreeBSDもバグ持ちと言うことだな。
0825名無しさん@お腹いっぱい。
2008/02/02(土) 13:20:240826名無しさん@お腹いっぱい。
2008/02/02(土) 13:27:40・set -uで警告が出る(ので回避する)
は排他じゃない。
>>811は、${1+"$@"}を空文字列への展開を避けるためと思い込んで、突っ込み(>>811)を
入れたのはいいが、set -uでの警告を知らなかったため、しどろもどろで反論を続けている。
かなり見苦しいぞ。www
> あと、未だに set -u で "$@" がエラーになる FreeBSDもバグ持ちと言うことだな。
FreeBSDだけじゃなく、Solaris10でも同じように警告が出るぞ。
ところで、お前が試したashって何処のashだよ。
ash -> bashじゃねーのか? www
0827名無しさん@お腹いっぱい。
2008/02/02(土) 14:21:040828名無しさん@お腹いっぱい。
2008/02/02(土) 14:42:22・>>811 ${1+"$@"}という記法に因縁つける。
・>>810 反論のついでに「お前のプログラムってバグだらけだろう。」と煽る。>>812
・>>811 必死の再反論を試みるが迎撃され、逃亡。 <<=== 今ココ
0829名無しさん@お腹いっぱい。
2008/02/02(土) 15:06:570830名無しさん@お腹いっぱい。
2008/02/02(土) 15:35:02となってる。実際、ラッパーの類とか、皆 "$@"で書かれてるよ。
0831名無しさん@お腹いっぱい。
2008/02/02(土) 16:04:20・>>811 ${1+"$@"}という記法に因縁つける。
・>>810 反論のついでに「お前のプログラムってバグだらけだろう。」と煽る。>>812
・>>811 必死の再反論を試みるが迎撃され、逃亡。
・>>811 噴飯物の社内標準を持ち出す。 <<=== 今ココ
0832名無しさん@お腹いっぱい。
2008/02/02(土) 16:09:10set +u
hoge "$@"
って記述すれば委員じゃないの? 何がそんなに問題なの?
0833名無しさん@お腹いっぱい。
2008/02/02(土) 16:09:49ポータビリティと簡潔さのトレードオフだとは思うんだけど.
0834名無しさん@お腹いっぱい。
2008/02/02(土) 16:14:450835名無しさん@お腹いっぱい。
2008/02/02(土) 16:23:08特殊パラメータとして定義されている。
この定義は、たとえ位置パラメータの個数が0個の場合でも変わらない
(=未定義にはならない)ので、
$@は、位置パラメータの個数が0個の場合でも定義されていると考えられる。
よって、set -u 状態での $@ の参照を、
「未定義パラメータの参照」とみなしてしまう一部のシェルの実装は
バグと考えて良い。
0836名無しさん@お腹いっぱい。
2008/02/02(土) 16:25:45冗長な記述を否定するために、より冗長な記述を持ってきても説得力ないぞ。
しかも戻すために処理後にset -u必要だし。
いや、nounsetが設定されていることを確認しないといかんな。
if set -o | egrep 'nounset *on' >/dev/null 2>&1; then
set +u
hoge "$@"
set -u
else
hoge "$@"
fi
こうか? www
>>833
噴飯物の社内標準がなければ${1+"$@"}と書いても5文字増えるだけだ。
>>834
お前がやれ。理由は「社内標準が守れないから」とでもしとけ。www
0837名無しさん@お腹いっぱい。
2008/02/02(土) 16:33:04unsetできるのはシェル変数だけ。
それとは別に、「位置」パラーメータは未設定の場合もあり得る。
そして、$@は、「位置」パラーメータではなく
「特殊(←ここ重要)」パラメータであるということ。
set -u はそもそもシェル変数や「位置」パラーメータのように、
未設定である場合があり得るパラメータに対してチェックするためのもの。
その set -u が、「特殊」パラメータである $@ に反応してしまうのはおかしい。
0838名無しさん@お腹いっぱい。
2008/02/02(土) 16:35:51いや、その説明だと、特殊パラメータの $! は、バックグラウンド起動歴が
なければ未設定になるから、説明にならない。
>>835 の説明の方が正しいんじゃないか?
0839名無しさん@お腹いっぱい。
2008/02/02(土) 16:39:38↓こう主張してね。
> あと、引数が0の場合であっても現行のシェルなら "$@" ですべてOK。
> ${1+"$@"} という書き方はもう古いので、そろそろ撲滅すべし。
0840名無しさん@お腹いっぱい。
2008/02/03(日) 04:03:25ウチでは set -u 必須としてて環境的に ${1+"$@"} せざるを得ないんで
> 結論: ${1+"$@"} は不要
と言われても全然結論じゃないんだけどな "$@"にしたら問題起きるんで書き直しだし
まぁ言語仕様的には "$@" で問題起きない方が正しいのかもしれんが
シェル開発者や仕様企画者の集まりっていうならともかく
元々伝統的な方法でもあるんで必死こいて ${1+"$@"} を否定する意味が分からない
0841名無しさん@お腹いっぱい。
2008/02/03(日) 07:40:37set -u 必須ってどんな環境?
俺の認識では、set -u はあくまでデバッグ用であって、
本番スクリプトでset -uを記述するなんてあり得ないんだけどな。
で、set -u必須だったとして、例えば、あるオプション変数がセットされてれば
使うけど、セットされてなければ黙って無視したいような場合、
hoge_command $HOGE_OPT
って書いちゃ駄目なんだよね? (不便だな)
いちいち
hoge ${HOGE_OPT+HOGE_OPT}
って書くのかなw
0842名無しさん@お腹いっぱい。
2008/02/03(日) 08:20:12hoge ${HOGE_OPT+HOGE_OPT}
わらた
タイプミスで初期化してない変数を見てしまうバグが未然に防げる可能性があるだろ
0843名無しさん@お腹いっぱい。
2008/02/03(日) 08:42:59つねに ${HOGE_OPT+$HOGE_OPT} って書かなければならないルールになっちゃうから、
${HOGE_OPT+$HOGE_ORT} っていうタイプミスすると防げない。
0844名無しさん@お腹いっぱい。
2008/02/03(日) 08:58:040845名無しさん@お腹いっぱい。
2008/02/03(日) 08:59:22中身がないかどうかを set -u の状態で ifで判定ってできる?
0846名無しさん@お腹いっぱい。
2008/02/03(日) 09:09:300847名無しさん@お腹いっぱい。
2008/02/03(日) 09:16:38シェルスクリプト内部で定義する変数なら最初空文字列で初期化でいいけど、
起動時に環境変数で渡される変数だと、
結局セットされてるかどうかの判定が必要になるからあまり意味ないね
0848名無しさん@お腹いっぱい。
2008/02/03(日) 09:25:25if [ -n "$HOGE" ]; then
みたいなよくやる書き方もできないわけだ。
いちいち
if [ -n "${HOGE+$HOGE}" ]; then
って書くのかな?
あるいは最初にいちいち
: ${HOGE=}
とかするのかな。いずれにしても不便だなw
0849名無しさん@お腹いっぱい。
2008/02/03(日) 09:30:58[ -n "${HOGE+$HOGE}" ]
なんてしなくても、
[ -n "${HOGE-}" ]
で十分。
ところが、いつも${HOGE-}する癖がつくと結局 set -u の意味がなくなる。
rm -i をaliasしても無意味なのと似てる。
0850名無しさん@お腹いっぱい。
2008/02/03(日) 09:46:07俺は意味は分かるし、見かけたこともあるが、
なぜそんな冗長な書き方をしていたのかは
今の流れで初めて分かった。
で、set -u のバグがあるのは FreeBSD だけ?
0851名無しさん@お腹いっぱい。
2008/02/03(日) 11:13:41素人さんにプロのテクニックを教えてやろう。
set -uはタイプミスを検出するために使うんだよ。全ての変数は明示的に初期化する。
従って未定義の変数はタイプミスだ。
0852名無しさん@お腹いっぱい。
2008/02/03(日) 11:49:24なるほど。
一つ賢くなった気がする。
0853名無しさん@お腹いっぱい。
2008/02/03(日) 11:55:26その説明だと、未定義の場合もアリのスクリプトが書けない。
変数を他から引き継ぐ場合、初期化するわけにもいかない。
定義済みかどうかの判定がどこかで必要になる。
で、定義済みかどうかの判定自体が set -u に引っかかるから、
>>849 が指摘してるように冗長な記述が必要になる。
そこまで代償を払って set -u する必要もなかろう。
0854名無しさん@お腹いっぱい。
2008/02/03(日) 12:09:06> 変数を他から引き継ぐ場合、初期化するわけにもいかない。
> で、定義済みかどうかの判定自体が set -u に引っかかるから、
未定義ならば代入という記法があるので問題ない。(何度も出ているが${parameter=word})
いい加減に負け認めて引っ込みなよ。見苦しい。
・>>810 位置パラメータを用いた別解をだす。
・>>811 ${1+"$@"}という記法に因縁つける。
・>>810 反論のついでに「お前のプログラムってバグだらけだろう。」と煽る。>>812
・>>811 必死の再反論を試みるが迎撃され、逃亡。
・>>811 噴飯物の社内標準を持ち出すも撃破される。
・>>811 ムキになって反論するも、無知をさらけ出す結果に陥る。 <=== 今ココ
0855名無しさん@お腹いっぱい。
2008/02/03(日) 12:10:30>未定義ならば代入という記法があるので問題ない。
だから、その記述が冗長といってるんじゃないかw
0856名無しさん@お腹いっぱい。
2008/02/03(日) 12:16:23全ての変数は初期化するといってるだろ。
これが冗長だというならperlでも冗長だからuse strictしてないんだろうな。
「お前のプログラムってバグだらけだろう。」 www
0857名無しさん@お腹いっぱい。
2008/02/03(日) 12:17:16つうわけでアンケート.
変数は使うときまで宣言しない派?最初に宣言しとく派?
0858名無しさん@お腹いっぱい。
2008/02/03(日) 12:20:39その場ですぐ使えるのがメリットだろ。
堅苦しく変数宣言必須にするならメリット半減だな。
0859名無しさん@お腹いっぱい。
2008/02/03(日) 12:21:080860名無しさん@お腹いっぱい。
2008/02/03(日) 12:28:27関数のローカル変数を設定する時ぐらいだな。
0861名無しさん@お腹いっぱい。
2008/02/03(日) 12:28:45それとも本文に set -u 入れてるの?
あまり見かけないけど
0862名無しさん@お腹いっぱい。
2008/02/03(日) 12:33:57キミのしょぼいスクリプトを基準に語られても困る。
0863名無しさん@お腹いっぱい。
2008/02/03(日) 12:36:43ずっと使っていくようなものも書ける
その幅の広さがシェルスクリプトのいいところじゃね?
0864名無しさん@お腹いっぱい。
2008/02/03(日) 13:47:22わからないから、なぜそう書くのか理解できない。
0865名無しさん@お腹いっぱい。
2008/02/03(日) 13:57:57なので、${1+"$@"}は位置パラメーター$1がセットされていると"$@"に展開される。
0866864
2008/02/03(日) 14:51:45ありがとう。manには:+しかなかったから別物だと思った。
見なおしたら"If the colon ( :) is omitted〜"って文があった。
www.cs.princeton.edu/~jlk/kornshell/doc/man88.html
0867名無しさん@お腹いっぱい。
2008/02/04(月) 21:43:38警告でないのはRedhat 4のashだけだ。FreeBSD 8も合わせてバグ報告しとけ。www
★SUSE LINUX Enterprise Server 9 (x86_64) p3
$ /bin/ash -cu 'echo "$@"'
/bin/ash: @: parameter not set
$ /bin/ksh -cu 'echo "$@"'
/bin/ksh: @: parameter not set
★Redhat 4 u5
$ /bin/ash -cu 'echo "$@"'
$ /bin/ksh -cu 'echo "$@"'
/bin/ksh: @: parameter not set
★Solaris10 8/07
$ /bin/sh -cu 'echo "$@"'
/bin/sh: @: parameter not set
$ /bin/ksh -cu 'echo "$@"'
/bin/ksh: @: parameter not set
$ /usr/xpg4/bin/sh -cu 'echo "$@"'
/usr/xpg4/bin/sh: @: parameter not set
★SFU(Service for UNIX) 3.5
$ /bin/sh -cu 'echo "$@"'
/bin/sh: @: parameter not set
$ /bin/ksh -cu 'echo "$@"'
/bin/ksh: @: parameter not set
0868名無しさん@お腹いっぱい。
2008/02/04(月) 21:46:31もはやこれは愛だな
0869名無しさん@お腹いっぱい。
2008/02/04(月) 22:03:43file1に入っている文字を、file2の中で検索し、あればエラーなしという
スクリプトを書きたいのですが、どなたかご教授願えないでしょうか?
file1には以下のような文字が200行程度、入っています。
aaa 12345678
bbb 12345678
ccc 12345678
file2には以下のような文字が300行程度入っております。
aaa 09876543
bbb 09876543
ccc 09876543
ddd 09876543
このfile1に入っている頭3文字の行全てを、file2の頭3文字にあるかないか、
といったスクリプトを書きたいのですが、シェルの基本程度しかしらず
悪戦苦闘をしております。なにとぞ、ご教授願いますよう、お願いします。
0870名無しさん@お腹いっぱい。
2008/02/04(月) 22:11:16kshじゃなくても、普通のshで書けるね。
↓
#!/bin/sh
while read key other
do
if grep -q $key file2; then
echo "$key は file2にある"
else
echo "$key は file2にない"
fi
done < file1
0871869
2008/02/04(月) 22:16:58さらに運悪くジョブ管理までやらされるはめに。
ご迷惑をおかけしますが、何卒よろしくお願いします
0872名無しさん@お腹いっぱい。
2008/02/04(月) 22:17:480873名無しさん@お腹いっぱい。
2008/02/04(月) 22:18:56だったら #!/bin/ksh って書けばいいだけだよ。
あと、grep -q $key は grep -q "^$key" の方がいいかな。
0874名無しさん@お腹いっぱい。
2008/02/04(月) 22:19:520876名無しさん@お腹いっぱい。
2008/02/04(月) 22:24:19こいつ、ネタか?
この場合、kshで書いても shと全く同じものになるんだよ。
それとも、何か最低限 ksh専用の文法を使わなけりゃいかんのかよ?
0877869
2008/02/04(月) 22:32:56丁寧に答えてくださり、まことに感謝しております。
>>876様
何分Kshの事を全然知らなくて…
Goto文が書けないやら、色々戸惑っている最中です。
もし何かまたわからない事がありましたら、ご質問させていただきます。
今回は本当にありがとうございました。
0878名無しさん@お腹いっぱい。
2008/02/04(月) 22:41:33偶然ですが、>>870 と同じようなスクリプトを書くために悪銭苦闘しています。
とりあえず /bin/shでではできたんですが、
今後はbashシェルで書けとの命令が上から下りまして…
>>870 をbashシェルで書くとどのようになりますでしょうか、ご教授ください。
なお、#!/bin/shを#!/bin/bashに変えただけでは却下され、
何か最低限bashシェル専用の文法を使わなければ上司が納得してくれません。
0879名無しさん@お腹いっぱい。
2008/02/04(月) 23:26:500880名無しさん@お腹いっぱい。
2008/02/04(月) 23:44:18なぜsh互換ではNGでbash専用でないとダメなのか
その上司を問いつめて、結果をこのスレに書き込んでみ?
0881名無しさん@お腹いっぱい。
2008/02/05(火) 00:49:390882名無しさん@お腹いっぱい。
2008/02/05(火) 02:11:40まず
ttp://search.luky.org/linux-users.9/msg06102.html
とか嫁
0883名無しさん@お腹いっぱい。
2008/02/05(火) 02:30:35test とか [ を [[ 記法にでも変えたら?
0884名無しさん@お腹いっぱい。
2008/02/05(火) 03:10:05うっう〜
0885名無しさん@お腹いっぱい。
2008/02/05(火) 07:15:24testも[もないんだが、>>870 には。
0886名無しさん@お腹いっぱい。
2008/02/05(火) 09:47:50こんなの趣味でも書かないけどな。w
#!/bin/bash
while read line
do
grep "${line:0:3}" file2 &> /dev/null
if $[ $? == 0 ] ; then
echo "$key は file2にある"
else
echo "$key は file2にない"
fi
done <<< "$( < file1 )"
0887名無しさん@お腹いっぱい。
2008/02/05(火) 09:49:48けど、こんなの使わないからいいか。w
0888名無しさん@お腹いっぱい。
2008/02/05(火) 10:19:410889名無しさん@お腹いっぱい。
2008/02/05(火) 10:33:290890名無しさん@お腹いっぱい。
2008/02/05(火) 10:56:19他の環境どころか、明日はもう動かなくていいやつとか。
0891名無しさん@お腹いっぱい。
2008/02/05(火) 12:31:070892名無しさん@お腹いっぱい。
2008/02/06(水) 13:18:18のようなものの-not -regex ".*#.*" -not -name "*~" -not -name "*svn*"の部分だけを再利用したいんですが
ignore_backup="-not -regex \".*#.*\" -not -name \"*~\" -not -name \"*svn*\""
のようにして
$ find $FOO $ignore_backup -name "*.el"
としてもうまくフィルタリングしてくれないようです
何が良い方法はありませんか?
0893名無しさん@お腹いっぱい。
2008/02/06(水) 13:33:030894名無しさん@お腹いっぱい。
2008/02/06(水) 14:01:270895名無しさん@お腹いっぱい。
2008/02/06(水) 14:10:12evalすると言う手でなんとかしました
zsh,bashでしか確認してませんがとりあえずこんな感じでいけました
この方針なら内部で他の変数を参照する予定の無い文字列はsingle quoteにした方がよさそうですね
# dot files
ignore_bkup='-type f -not -regex ".*#.*" -not -name "*~"'
eval "$find $HOME -maxdepth 1 $ignore_bkup -regex '.*\/\..*'"
0896名無しさん@お腹いっぱい。
2008/02/06(水) 14:19:360897名無しさん@お腹いっぱい。
2008/02/06(水) 19:47:26引数にlistという文字列がある場合には、lsコマンドを実行する
これを実行するにはどういう構文をつくればいいのでしょうか?
0898名無しさん@お腹いっぱい。
2008/02/06(水) 20:05:04for arg in "$@"
do
case $arg in
list)
ls;;
esac
done
0899名無しさん@お腹いっぱい。
2008/02/06(水) 20:22:09ありがとうございます
0900名無しさん@お腹いっぱい。
2008/02/06(水) 23:46:40$args → "$args"
0901名無しさん@お腹いっぱい。
2008/02/06(水) 23:47:18お前馬鹿だろ
0902名無しさん@お腹いっぱい。
2008/02/07(木) 00:30:09> 何か最低限bashシェル専用の文法を使わなければ上司が納得してくれません。
お前に必要なのは不要な文法ではなくて新しい職。
0903名無しさん@お腹いっぱい。
2008/02/07(木) 04:59:080904名無しさん@お腹いっぱい。
2008/02/07(木) 09:35:36$ echo .string | sed -e s/^\\\\.//
.string
(2)
$ AAA=.string
$ BBB=
$ BBB=`echo "$AAA" | sed -e s/^\\\\.//`
$ echo $BBB
string
(1)(2)で結果が違ってくるのですがこれはなぜでしょうか。
0905名無しさん@お腹いっぱい。
2008/02/07(木) 09:48:23を使っているから。
0906名無しさん@お腹いっぱい。
2008/02/07(木) 09:49:180907名無しさん@お腹いっぱい。
2008/02/07(木) 09:55:550908名無しさん@お腹いっぱい。
2008/02/09(土) 01:16:110909名無しさん@お腹いっぱい。
2008/02/11(月) 14:50:12unixのwc -lコマンドと同等のものを
perlやawkの一行野郎にしたいのですがうまくいきません
perl -ne 'while (<>) { print cnt}' file1
お願いします
0910名無しさん@お腹いっぱい。
2008/02/11(月) 14:55:300911名無しさん@お腹いっぱい。
2008/02/11(月) 14:58:34awk使いたいだけなら、
cat file1 | cat -n | tail -1 | awk '{print $1}'
でいいじゃん。
0912名無しさん@お腹いっぱい。
2008/02/11(月) 15:00:280913名無しさん@お腹いっぱい。
2008/02/11(月) 15:03:27cat file | cat -n
ってところかい?
それは最初のcatは、catじゃなくても他の部分から取れるようにしてるのだが。
0914名無しさん@お腹いっぱい。
2008/02/11(月) 15:03:40awk 'END{print NR}' file
0915名無しさん@お腹いっぱい。
2008/02/11(月) 15:04:54無駄ってのは、>>914 でできるのにわざと冗長な方法を書いていること。
0916名無しさん@お腹いっぱい。
2008/02/11(月) 15:05:560917名無しさん@お腹いっぱい。
2008/02/11(月) 15:08:23要求をはっきりしたまえ。
もっとも、↓これなら完璧だが。
perl -e 'exec "wc", "-l", @ARGV'
0918名無しさん@お腹いっぱい。
2008/02/11(月) 15:09:44みんなで考察してみようぜ。
まず、どこから急にcntが出て来たのか。
0919名無しさん@お腹いっぱい。
2008/02/11(月) 15:11:25>>911でいいじゃないか。
思い付いたようにシンプルに済ませるのがShellScriptでしょ。
0920名無しさん@お腹いっぱい。
2008/02/11(月) 15:12:23サーバ環境のコードに合わない文字コードのファイルだと
wcコマンド使えないので他に代用したいというのが背景です。
目的はファイルの行数を単にカウントするだけです。
レス数が900を超えています。1000を超えると表示できなくなるよ。