シェルスクリプト総合 その8
■ このスレッドは過去ログ倉庫に格納されています
0001名無しさん@お腹いっぱい。
2007/02/15(木) 14:28:44スクリプトのお勉強・自慢・腕試しなどにどうぞ。
まずは注意点、リンク、地鎮祭など(>>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 でトレースしましょう。
前スレ
シェルスクリプト総合 その7
http://pc10.2ch.net/test/read.cgi/unix/1157601611/
0727名無しさん@お腹いっぱい。
2007/06/27(水) 02:31:28Solarisの/bin/shはそれこそSystemV7のころのものとほとんど変わっていない。
0728名無しさん@お腹いっぱい。
2007/06/27(水) 03:37:470729名無しさん@お腹いっぱい。
2007/06/27(水) 07:44:21じゃなくて、シングルユーザーモードの時、
/sbin/shはあるが、
/sbin/kshは無い。
/sbin/shはstatic linkの/bin/sh(/usr/bin/sh)
だから、シングルユーザーモードも含めれば、
結局 /bin/shの文法の範囲で書かざるを得ないという話。
しかも、Solarisの/bin/shは古いままなので、
export a=b も、$(command)も test -e も、
ちょっと新しい書き方はすべて使えない。
0730名無しさん@お腹いっぱい。
2007/06/27(水) 08:03:47一部のスクリプトで、未だに
${1+"$@"} って書いてあるのがある。
これ、もう "$@" でいいんじゃないか?
引数が0個の時に ""が残らないようにする措置だろうけど、
Solarisの/bin/shですらそんな不具合は発生しない。(確認済み)
なので、"$@"と書いて問題ないし、視認性上も "$@"と書くべきと思うんだが。
本当に ${1+"$@"}と書く必要がある /bin/shを搭載したOSって、
現存してる?
0731名無しさん@お腹いっぱい。
2007/06/27(水) 22:07:07なんか Solaris のシングルユーザモードって不便そうですね。
CD 6枚焼いたけど、インストールを躊躇してしまうよ。
0732名無しさん@お腹いっぱい。
2007/06/27(水) 22:19:420733名無しさん@お腹いっぱい。
2007/06/27(水) 23:07:41なるほどねぇ、知らんかったよ。ありがと。
>>730
書き換えるのが面倒なだけなんじゃないか?
目障りだと思うなら、君が片っ端から書き換えて動作検証してあげればいいと思う。
0734名無しさん@お腹いっぱい。
2007/06/27(水) 23:19:19すんません BSD ユーザなもので、 / と /usr を分けるというのが
イマイチ良く解かりません。
ad0s1a に全部突っ込めって事ですか?
/var も /tmp も含めて・・・(よーするに swap 以外は同じパーテーション?)
Solaris だとそんなの有りなんだぁ。(BSDでも無いことは無いけど、なんだか・・)
0735名無しさん@お腹いっぱい。
2007/06/27(水) 23:36:430736名無しさん@お腹いっぱい。
2007/06/27(水) 23:43:05でも、その好みの問題に対して Solaris はシングルユーザモードの
挙動をもってして、ユーザに介入してくる分けでしょう?
>>732 のレスからは、そういう風に読めるのだが?
0737名無しさん@お腹いっぱい。
2007/06/28(木) 00:09:080738名無しさん@お腹いっぱい。
2007/06/28(木) 05:10:23>>730 の ${1+"$@"} てどうゆう意味なの??
なんか理解できん・・・(TT
0739名無しさん@お腹いっぱい。
2007/06/28(木) 05:18:04NetBSDのデフォルトは分けないからBSDユーザーってのは言い訳にならない。
0740名無しさん@お腹いっぱい。
2007/06/28(木) 07:33:15if [ X$HOGE = X ]
なんてのも見かける。これも、
if [ "$HOGE" = '' ]
と書いたほうがいい。
むかーしのバージョンのtestで、$HOGEの内容が = だったような場合、
[ = = '' ] みたいになるとエラーになるtestに対する対処として、
X$HOGE とかいう回避法があったけど、今の testコマンドでそれが必要なのは
もう現存しないはず。
0741名無しさん@お腹いっぱい。
2007/06/28(木) 14:01:16ちがう。
$HOGE の内容が -f だったような場合に対する対処だから、今でも有効。
0742名無しさん@お腹いっぱい。
2007/06/28(木) 14:16:42$HOGE の内容が -f でも正常に動くんだけど。
[ -f = hoge ] みたいに、項が3つある時は、
-fはファイル存在オプションとはみなされないから
-f だった時駄目になるような/bin/sh搭載した OSって 何?
0743名無しさん@お腹いっぱい。
2007/06/28(木) 14:36:59a="-f"
b="-a"
c="="
d=""
test X"$a" = X"$b" -a X"$c" = X"$d"
echo $?
test $a = $b -a $c = $d
echo $?
FreeBSD の ash、Solaris の sh, ksh、GNU bash いずれでも異なる結果になりました。
0744名無しさん@お腹いっぱい。
2007/06/28(木) 14:39:58それは、複数の式を -a (AND) でつないだ場合の話。
それだと確かに式の評価がおかしくなることがあるが、
[ $HOGE = hoge ] なら、X$HOGE とする必要はなし。
Solarisの/bin/sh でも [ -f = -f ] は無問題。
0745名無しさん@お腹いっぱい。
2007/06/28(木) 14:43:14一律で X$HOGE にしといた方がおしゃれ。
0746名無しさん@お腹いっぱい。
2007/06/28(木) 14:48:53-a 使う場合は、各評価式ごとに \( \) で括るのを推奨。
[ \( "$a" = "$b" \) -a \( "$c" = "$d" \) ]
↑みたいにね。これで、X"$HOGE" は不要。
0747名無しさん@お腹いっぱい。
2007/06/28(木) 14:54:19> [ $HOGE = hoge ] なら、
クォート忘れてる。
> X$HOGE とする必要はなし。
ダウト。
そのへんの対バカ性能をどこまで頑張るかはヒューリスティックで実装依存。
たとえばFreeBSDのtestでは
$ HOGE='!'
$ [ "$HOGE" = hoge ]; echo $?
[: =: unexpected operator
2
となるので変数に任意の値を想定するなら "X$HOGE" = Xhoge は依然必要。
常にtestの引数が正しい式となるよう書くにしくはなし。
0748名無しさん@お腹いっぱい。
2007/06/28(木) 15:06:47>>730 についてはどうお考え?
${1+"$@"} は以前必要? もう不要で "$@"で桶?
0749名無しさん@お腹いっぱい。
2007/06/28(木) 15:09:08どこ使うんだろ。
0750名無しさん@お腹いっぱい。
2007/06/28(木) 17:18:000751名無しさん@お腹いっぱい。
2007/06/28(木) 17:20:300752名無しさん@お腹いっぱい。
2007/06/28(木) 17:25:52case $HOGE in hoge) にするなぁ。
caseだと、たとえ$HOGEの中身が ! だとか -f -a とか特殊記号だったとしても
すべて無問題だから。
0753名無しさん@お腹いっぱい。
2007/06/28(木) 17:31:27詳解シェルスクリプトを企画するか
0754名無しさん@お腹いっぱい。
2007/06/28(木) 17:35:220755名無しさん@お腹いっぱい。
2007/06/28(木) 17:37:220756名無しさん@お腹いっぱい。
2007/06/28(木) 17:38:150757名無しさん@お腹いっぱい。
2007/06/28(木) 17:39:17本売るつもりなら大事でしょ。
0758名無しさん@お腹いっぱい。
2007/06/28(木) 17:40:070759名無しさん@お腹いっぱい。
2007/06/28(木) 17:41:25>>756 が言ってるのは、ユーザーがシェルの互換性に興味あるのか? ってことでは
(需要に興味があるかどうかじゃなく)
0760名無しさん@お腹いっぱい。
2007/06/28(木) 17:49:09何冊くらい売れるんだ?
このスレでも>>4にある本の話なんて全然出ないし。
0761名無しさん@お腹いっぱい。
2007/06/28(木) 17:50:30そういうの読む人がここの話に参加しづいらいだけで。
0762名無しさん@お腹いっぱい。
2007/06/28(木) 17:52:470763名無しさん@お腹いっぱい。
2007/06/28(木) 17:59:17よほど古いシェルじゃない限り互換性ある。でもなぜか出番なくてあまり使わない。
0764名無しさん@お腹いっぱい。
2007/06/28(木) 18:02:34意外に受けたらしいから
0765名無しさん@お腹いっぱい。
2007/06/28(木) 18:11:11使ってるの見たことないコマンドの筆頭が readonly だな。
0766名無しさん@お腹いっぱい。
2007/06/28(木) 18:12:21ありがとうございます。
もうひとつ質問なんですが、ポータブルかつ安全に一時ファイルを作成するにはどうすればいいのでしょうか。
0767名無しさん@お腹いっぱい。
2007/06/28(木) 18:12:31もうこの分野で出ても意味ないわな。
カーニハン&パイクとブルース・ブリンけあればいいんじゃないか。
0768名無しさん@お腹いっぱい。
2007/06/28(木) 18:17:41どこまでの安全性を言ってるのかわからないけど、
(unask 77; > /tmp/hoge$$)
じゃだめかい?
mktempコマンドは、必ずしもあるとは限らないと仮定するべきなのだろうか?
0769名無しさん@お腹いっぱい。
2007/06/28(木) 18:21:56実用上はほとんど問題にならないのでしょうが、気持ち悪いので何か安全な方法があるのかお尋ねしました。
0770名無しさん@お腹いっぱい。
2007/06/28(木) 18:31:34mkdirとかでちゃんとロックして、
失敗したら別の名前で試すとかするしかない。
作るディレクトリのパーミッションちゃんとしとけば
推測されてもかゆくもないでしょ。
0771名無しさん@お腹いっぱい。
2007/06/28(木) 18:49:360772名無しさん@お腹いっぱい。
2007/06/28(木) 19:09:45/dev/urandom はポータブルではないわけで、、
0773名無しさん@お腹いっぱい。
2007/06/28(木) 19:10:47>>771
catが無駄です。
0774名無しさん@お腹いっぱい。
2007/06/28(木) 19:45:410775名無しさん@お腹いっぱい。
2007/06/28(木) 19:53:310776名無しさん@お腹いっぱい。
2007/06/28(木) 20:07:270777名無しさん@お腹いっぱい。
2007/06/28(木) 20:09:050778名無しさん@お腹いっぱい。
2007/06/28(木) 20:13:150779名無しさん@お腹いっぱい。
2007/06/29(金) 01:27:29ていうか、間違いだらけの知識を持ってるやつほどSolarisをバカにする傾向があるな。
0780名無しさん@お腹いっぱい。
2007/06/29(金) 01:33:43Sol10 からね。Sol9 までは static link。
0781名無しさん@お腹いっぱい。
2007/06/29(金) 03:23:19の間違いでした
0782名無しさん@お腹いっぱい。
2007/06/30(土) 16:06:14747じゃないけど "$@" -> ${1+"$@"} とするのは set -u でもエラーにならない為かと
すくなくともある環境では0を除いた位置変数が未設定なら前者はパラメータ未設定エラーになるから
別に""の互換性の理由だけで${1+"$@"}にする訳ではないでしょ
0783782
2007/06/30(土) 16:14:29正) 為でもあるかと
0784名無しさん@お腹いっぱい。
2007/06/30(土) 17:05:31実際に ${1+"$@"} が使われてるのは set -u のところじゃない。
コマンドのラッパーで引数を渡す時の話。
なので、>>782 の話は当たっていない。
0785名無しさん@お腹いっぱい。
2007/06/30(土) 17:10:16空文字列が残らないようにするため。
他に、${@+"$@"} という書き方もある(あった)。
今議論になってるのはそこじゃなくて、
未だに ${1+"$@"} が必要なシェルが現存しているかどうか、
現存しているなら そのOS名は? という質問。
0786名無しさん@お腹いっぱい。
2007/06/30(土) 17:59:27「でもあるかと」と訂正してるんだが
実際 set -u 設定状態でコマンドラッパーに"$@"で渡そうとしても
$@ を評価(展開)する段階で未設定と判定された訳で
空文字列が残るかどうかなんて今時大抵解消されてるでしょ
幾つかのOS、幾つかのB系シェルを触ったことはあるけど個人的には見たことがない
ただ単純に ${1+"$@"} -> "$@" として問題ないか?と聞かれたら
set -u で問題が起きるからダメだと
0787名無しさん@お腹いっぱい。
2007/06/30(土) 18:24:29で、その set -u で問題が出たOSって何?
0788782
2007/06/30(土) 18:25:32もともと空文字列対応で今時 ${1+"$@"} とする必要はあるか?かもしれんが、
たとえその為の対応が不要になったとしても、${1+"$@"} -> "$@" にしていいことにはならんよと言いたい
理由は以下のスクリプトを実行するとエラーになる環境もあるからと
#!/bin/sh
set -u
echo "$@"
0789名無しさん@お腹いっぱい。
2007/06/30(土) 18:29:44だから、そのエラーになる環境は何なのかと。
俺のところの *BSD/Solarisとあと犬で、エラーになるのはひとつもないのだが。
0790名無しさん@お腹いっぱい。
2007/06/30(土) 18:56:23そのSolarisじゃないの? ほんとに試してみた? バージョンによるのかな?
結局互換性の最大の問題はいつもSolarisだなww
0791名無しさん@お腹いっぱい。
2007/06/30(土) 20:36:50いまのSolarisをしらない奴がいてもしょうがない
0792名無しさん@お腹いっぱい。
2007/07/03(火) 01:38:27おそーーーーーーーーいので、あまり使いたくない。
0793名無しさん@お腹いっぱい。
2007/07/03(火) 12:33:550794名無しさん@お腹いっぱい。
2007/07/04(水) 12:36:32時代はmv /bin /ms.green
0795名無しさん@お腹いっぱい。
2007/07/04(水) 22:29:33test 1000000 -lt 9999999999
の結果が正にならないんだけど。数値型の値に制限とかあるのかな?
0796名無しさん@お腹いっぱい。
2007/07/04(水) 22:31:41bashだと無問題。「正」じゃなくて「真(0)」な。
0797名無しさん@お腹いっぱい。
2007/07/04(水) 22:35:060798名無しさん@お腹いっぱい。
2007/07/04(水) 22:35:10実装依存だな。シェルによっては 31bit整数最大の 2147483647 が扱える最大値。
0799名無しさん@お腹いっぱい。
2007/07/04(水) 22:37:55ありがと。ちなみに対処法って何かあったりする?違う言語使うしかないか。
0800名無しさん@お腹いっぱい。
2007/07/04(水) 22:42:13bcに喰わせるとか。bcだともっと大きい数まで扱える。
echo '1000000 < 9999999999' | bc
bcでは、testとは逆で、真の場合1になって、それが標準出力に出る。
0801名無しさん@お腹いっぱい。
2007/07/04(水) 22:55:380802名無しさん@お腹いっぱい。
2007/07/05(木) 22:47:110803名無しさん@お腹いっぱい。
2007/07/05(木) 23:01:130804名無しさん@お腹いっぱい。
2007/07/06(金) 01:13:45(echo obase=2; echo 1.2.3.4 | tr '.' '\012') | bc | xargs -n 1 printf %.8d
0805名無しさん@お腹いっぱい。
2007/07/06(金) 01:23:00旧:(echo obase=2; echo 1.2.3.4 | tr '.' '\012') | bc | xargs -n 1 printf %.8d
新:printf %d%.8d%.8d%.8d `echo obase=2.1.2.3.4 | tr . \; | bc`
0806名無しさん@お腹いっぱい。
2007/07/06(金) 10:00:27tcsh では $ test.sh で動作するのに、
bash では $ test.sh で動作せず、
$ bash -c test.sh でも動作しませんでした。
/usr/local/bin/以下に置いたところ、
bash上の $ test.shは動作しましたが、
やはり、$ bash -c test.sh は動作しません。
この原因は、どのあたりにあるのでしょうか。
ヒントでよいので教えてください。
0807名無しさん@お腹いっぱい。
2007/07/06(金) 10:26:25(t)cshと(ba)sh では、PATHの変数が違う。本当はPATHを通し忘れているというオチ。
あるいは、.bashrcでPATHが再設定されてしまっているとか。
0808806
2007/07/06(金) 10:42:36bash上で、$ set | grep PATH すると、$HOME/binも入っているのですが、
やっぱり、PATH関係っぽいですよねぇ。
$ bash -c test.shができないのが気持ち悪いです。
ちなみに、$ $HOME/bin/test.sh では実行できました。
0809名無しさん@お腹いっぱい。
2007/07/06(金) 10:46:13setじゃなくて、printenvで確認した方がいい。
シェル変数のPATHのみセットされていて、exportされてない可能性がある。
すると、bash -c とかやった時、新しいbashにはPATHが引き継がれないから、
そういう現象が起きる。
0810806
2007/07/06(金) 10:59:27exportされないというのは盲点でした。
おっしゃるとおり、
$ printenv | grep PATH
をしたところ、$HOME/binも含まれていました。
一応、.bashrcでの設定はきいているんですよね。
ググったところ、Cygwin上では、
bashのバグ?かなにかで、bash -c がきかない現象があるようです。
遅くなりましたが、自分の環境は linux 、bash 3.1 です。
0811名無しさん@お腹いっぱい。
2007/07/06(金) 11:09:470812806
2007/07/06(金) 12:10:14席を外していまして、遅くなってすいません。
スクリーンダンプは以下のようなものでよろしいでしょうか。
実はtest.shは、navi2chインライン画像表示のためのシェルスクリプトで引数もとります。
i) bash上で実行
$ bash --verbose -c navi2ch.makethumb http://www.google.co.jp/intl/ja_jp/images/logo.gif
navi2ch.makethumb
$ sh -x navi2ch.makethumb http://www.google.co.jp/intl/ja_jp/images/logo.gif
+ tmp=/tmp/navi2ch-thumbnails
+ origfile=/tmp/navi2ch-thumbnails/www.google.co.jp/intl/ja_jp/images/logo.gif
+ thumbfile=/tmp/navi2ch-thumbnails/www.google.co.jp/intl/ja_jp/images/logo.gif.jpg
+ thumbsize=300x150
+ '[' '!' -f /tmp/navi2ch-thumbnails/www.google.co.jp/intl/ja_jp/images/logo.gif ']'
+ '[' -z '' ']'
+ /usr/bin/wget http://www.google.co.jp/intl/ja_jp/images/logo.gif -q -N -x -P /tmp/navi2ch-thumbnails
+ '[' '!' -f /tmp/navi2ch-thumbnails/www.google.co.jp/intl/ja_jp/images/logo.gif.jpg
+ thumbsize=300x150
+ '[' '!' -f /tmp/navi2ch-thumbnails/www.google.co.jp/intl/ja_jp/images/logo.gif ']'
+ '[' -z '' ']'
+ /usr/bin/wget http://www.google.co.jp/intl/ja_jp/images/logo.gif -q -N -x -P /tmp/navi2ch-thumbnails
+ '[' '!' -f /tmp/navi2ch-thumbnails/www.google.co.jp/intl/ja_jp/images/logo.gif ']'
++ identify -format %n /tmp/navi2ch-thumbnails/www.google.co.jp/intl/ja_jp/images/logo.gif
+ scene=1
+ '[' '!' -s /tmp/navi2ch-thumbnails/www.google.co.jp/intl/ja_jp/images/logo.gif.jpg -o /tmp/navi2ch-thumbnails/www.google.co.jp/intl/ja_jp/images/logo.gif.jpg -ot /tmp/navi2ch-thumbnails/www.google.co.jp/intl/ja_jp/images/logo.gif ']'
+ '[' 1 -gt 1 ']'
+ convert -sample 300x150 /tmp/navi2ch-thumbnails/www.google.co.jp/intl/ja_jp/images/logo.gif /tmp/navi2ch-thumbnails/www.google.co.jp/intl/ja_jp/images/logo.gif.jpg
+ echo -n /tmp/navi2ch-thumbnails/www.google.co.jp/intl/ja_jp/images/logo.gif.jpg
/tmp/navi2ch-thumbnails/www.google.co.jp/intl/ja_jp/images/logo.gif.jpg
0813806
2007/07/06(金) 12:13:07上の方の
$ bash --verbose -c
では、画像は取得されませんでした。
下の方の
$ sh -x
は、画像が取得されました。
0814名無しさん@お腹いっぱい。
2007/07/06(金) 12:18:15フルパス指定じゃだめ?
0815名無しさん@お腹いっぱい。
2007/07/06(金) 12:32:040816名無しさん@お腹いっぱい。
2007/07/06(金) 12:39:22test.shが問題だというから、
ちゃんと問題を切り分けて小さくしてるのかと思ったら、それかよ
.bashrcの中身も、printenv PATH そのものも、隠さず出したら?
0817806
2007/07/06(金) 12:52:00もう一度試したところ、bash上でも
$ navi2ch.makethumb 引数
が実行できました。
しかし、
$ bash -c navi2ch.makethumb 引数
は、やはり実行できませんでした。
>>814
フルパス指定だとbash上でも実行できます。
一応、回避策として、/usr/local/bin/に置いているので、具体的な支障はないのですが、
"bash -c"だけがうまく動いてくれないのはなぜだろうと不思議に思って、質問しました。
だから、本当はこんなにレスしていただくほどのことでなくて、申し訳ないです。
>>815
nkf でチェックしたところ、EUC-JPでした。(環境はja_JP.UTF-8)
cat -v で見ても、改行コードらしきものはありませんでした。
0818名無しさん@お腹いっぱい。
2007/07/06(金) 13:06:23bash -c 'navi2ch.makethumb 引数'
じゃないと駄目だろ
0819806
2007/07/06(金) 13:07:41#!/bin/sh
echo test
のようなシェルスクリプトですと、~/bin/以下に置いて、
$ bash -c test.sh
test
と実行できます。
$ printenv PATH
/home/mona/bin:/usr/local/bin:/usr/bin:/bin:/usr/bin/X11:/usr/games
ふだんbashを使っていないので、~/.bashrcはありものです。
~/.bashrc
PATH=$HOME/bin:$PATH
↑とりあえず、これだけにしました。
これでもやはり、
$ bash -c navi2ch.makethumb http://www.google.co.jp/intl/ja_jp/images/logo.gif
では画像を取得できませんでした。
"bash -c"はいろいろときびしそうですね。
0820806
2007/07/06(金) 13:12:21$ bash -c 'navi2ch.makethumb 引数'
で画像を取得出来ました。
超基本的なことに気付かず、おさわがせして申し訳ないです。
どうもすみませんでした。
ほんとうにごめんなさい。
0821名無しさん@お腹いっぱい。
2007/07/15(日) 17:20:37(sleep $ALIVE_TIME; ps $$ && kill -INT $$; sleep 1; ps $$ && kill -KILL $$)
1秒待ってもう1度だけkillしてるのはなぜなんですかね?
0822名無しさん@お腹いっぱい。
2007/07/15(日) 17:56:03よく見ろ。-INT と -KILL で違うだろ。
0823名無しさん@お腹いっぱい。
2007/07/15(日) 22:02:120824名無しさん@お腹いっぱい。
2007/07/16(月) 22:04:04sedなどを使ってやればできないことはないですが、
if文一発でできればいいなと。。
0825名無しさん@お腹いっぱい。
2007/07/16(月) 22:07:47できない。
正規表現と言ってるが、実際にはワイルドカードで十分なことが多い。
ワイルドカードなら ifの代わりに caseを使えばできる。
0826名無しさん@お腹いっぱい。
2007/07/16(月) 22:08:01■ このスレッドは過去ログ倉庫に格納されています