シェルスクリプト総合 その7
■ このスレッドは過去ログ倉庫に格納されています
0001ミスターシェル
2006/09/07(木) 13:00:11スクリプトのお勉強・自慢・腕試しなどにどうぞ。
まずは注意点、リンク、地鎮祭など(>>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 でトレースしましょう。
0400名無しさん@お腹いっぱい。
2006/11/20(月) 19:22:210401名無しさん@お腹いっぱい。
2006/11/20(月) 19:44:220402名無しさん@お腹いっぱい。
2006/11/20(月) 19:46:36のフォームで報告しときゃいいんじゃね。
0403名無しさん@お腹いっぱい。
2006/11/20(月) 21:19:03読んで調べるぐらいした方がいいぞ。
0404名無しさん@お腹いっぱい。
2006/11/21(火) 00:06:55最近シェルスクリプト始めたのですがわからないことが
あって困っています。
小数の比較ってどうすればできるんですか?
---------------------------------------
#!/bin/bash
if [ 0.0001 -ge 0.00001 ]
then
echo "success"
fi
---------------------------------------
という風に書いて実行するとinteger expression expectedが出てしまうんで
すけど、どうしたらいいのでしょうか?
0405名無しさん@お腹いっぱい。
2006/11/21(火) 00:21:31整数で比較する
0406名無しさん@お腹いっぱい。
2006/11/21(火) 00:26:08あきらめろ。
awkやperlなど使うしかないだろ。
0407名無しさん@お腹いっぱい。
2006/11/21(火) 00:39:35evalつかえばなんでもできるって…
0408名無しさん@お腹いっぱい。
2006/11/21(火) 00:42:06-.*)
echo fail
;;
*)
echo success
;;
esac
0409名無しさん@お腹いっぱい。
2006/11/21(火) 02:31:42元ファイルを加工して1レコードが2フィールドで
接続開始時刻:接続終了時刻
の形式のファイルをawkを使って抽出してあります。
時刻は数値化(Excelの日付表示を数値表示に変換したもの)
されているので直接比較可能です。
スクリプトで処理したい作業は
あるレコードの接続開始時刻から接続終了時刻の間に
A 全レコード中、接続開始時刻が何件含まれているか
B 全レコード中、接続終了時刻が何件含まれているか
を各レコードの情報とともに表示させることです。
接続開始時刻:接続終了時刻:A件数:B件数
みたいに。
実際には同時接続数がどれぐらいあるかチェックしたいので
おおざっぱに掴めればなあと。
awkでレコードを1行読むごとに、全行比較という形で
スクリプトを書きかけたのですが、そもそも全行と
比較できず終わってしまっているようです。
{x=0;y=$1;z=$2;if ($1<=y && z<=$2) x=x+1;print x}
readlineが必要そうであれこれ試しているのですが、
こちらは全く使ったことがないので苦戦しています。
どなたかお知恵拝借させてください。
0410名無しさん@お腹いっぱい。
2006/11/21(火) 06:04:41まず
> A 全レコード中、接続開始時刻が何件含まれているか
> B 全レコード中、接続終了時刻が何件含まれているか
を実現する関数かスクリプトを作って
レコードを1行読むごとにそれを実行する、という方法はどう?
awk で関数なんて作ったことないから外しているかも。
0411名無しさん@お腹いっぱい。
2006/11/21(火) 09:49:42時刻 接続開始or終了
という形式のレコードを時刻でソートしてから頭からなめて
開始が来たら同時接続数++,
終了が来たら同時接続数--
としたほうが簡単じゃないか。
0412名無しさん@お腹いっぱい。
2006/11/21(火) 13:12:300413名無しさん@お腹いっぱい。
2006/11/21(火) 22:33:38どうすればいいんでしょうか?
0414名無しさん@お腹いっぱい。
2006/11/21(火) 22:49:550415名無しさん@お腹いっぱい。
2006/11/21(火) 22:52:060416名無しさん@お腹いっぱい。
2006/11/21(火) 22:57:010417名無しさん@お腹いっぱい。
2006/11/21(火) 22:59:240418名無しさん@お腹いっぱい。
2006/11/21(火) 23:05:44ファイル名に -> が入っている場合はアウトかと思っていましたが
やってみたらOKでした。ありがとうございます。
0419名無しさん@お腹いっぱい。
2006/11/23(木) 00:32:530420名無しさん@お腹いっぱい。
2006/11/23(木) 00:48:18全ての環境で共通に動かせるようにする道は死屍累々ですから。
0421名無しさん@お腹いっぱい。
2006/11/23(木) 02:53:37笑止。
真にマルチプラットフォームな言語なぞ無い。
0422名無しさん@お腹いっぱい。
2006/11/23(木) 09:16:15動かなかったら直せばいいだけ。
0423名無しさん@お腹いっぱい。
2006/11/23(木) 11:42:56所詮テキストファイルだし。
0424名無しさん@お腹いっぱい。
2006/11/23(木) 13:32:35異なる環境で動かすことを考えて作成されたシェルスクリプトに限定すれば真。
0425名無しさん@お腹いっぱい。
2006/11/23(木) 13:58:380426名無しさん@お腹いっぱい。
2006/11/23(木) 14:04:16いまでもアセンブリ書くよりはるかにポータブルだが…
0427名無しさん@お腹いっぱい。
2006/11/23(木) 14:07:320428名無しさん@お腹いっぱい。
2006/11/23(木) 14:15:22Cコンパイラ自身がポータブル。
0429名無しさん@お腹いっぱい。
2006/11/23(木) 14:16:43C言語のソースはポータブルだが、バイナリはポータブルじゃない。
だから、実行形式そのままをポータブルにしたい場合は
Cを使わずにシェルスクリプトで書くというのが常識。
0430名無しさん@お腹いっぱい。
2006/11/23(木) 14:21:50そういう時は C で極力ポータブルに書く。
0431名無しさん@お腹いっぱい。
2006/11/23(木) 14:22:06シェルスクリプトにヒアドキュメントでCのソース埋め込めばポータブル。
0432名無しさん@お腹いっぱい。
2006/11/23(木) 14:24:090433名無しさん@お腹いっぱい。
2006/11/23(木) 14:24:46「バイナリが」と言ってるだろ。
どこの世界に、バイナリレベルでポータブルなCがあるんだよ???
0434名無しさん@お腹いっぱい。
2006/11/23(木) 14:27:19シェルスクリプトで書くのはシェルスクリプトで良いやと判断した時だけ。
0435名無しさん@お腹いっぱい。
2006/11/23(木) 14:37:160436名無しさん@お腹いっぱい。
2006/11/23(木) 14:47:110437名無しさん@お腹いっぱい。
2006/11/23(木) 14:50:41という意味ではポータブルではない。
同様のことがperlとかにも言える。
シェルがインストールされていない環境はあり得ないので、
そういう意味でシェルスクリプトが最もポータブル。
0438名無しさん@お腹いっぱい。
2006/11/23(木) 15:01:39bash に link されてる奴は論外として…
0439名無しさん@お腹いっぱい。
2006/11/23(木) 15:39:46シェルだけで完結することはほとんどない。
さまざまな外部コマンドを使うことによって機能を実現できる。
つまり外部コマンドの仕様や配置などによって修正を余儀なくされるから、
ポータビリティはかなり低い。
また、それとは別にシェルそのものの実装違いもあるし。
0440名無しさん@お腹いっぱい。
2006/11/23(木) 15:51:36それは人のレベルによる問題。
普段からポータビリティを気にしてシェルスクリプトを書いていれば、
たとえ外部コマンドを使うにしても、どのOSでも使えるコマンドとオプションの
範囲だけで書く癖が付いているから、ポータビリティの高いスクリプトを
書くことは簡単にできる。逆に、別のOSで動かす予定がなかったのに、
たまたま別のOSでも動かす機会があった時に、そのまま動いてしまうことがほとんど。
一方、Java/perlとかだと、インストールされていなければそこで終り。
0441名無しさん@お腹いっぱい。
2006/11/23(木) 16:02:23シェルスクリプトがポータブルな範囲でのみ仕事を受け付けます。
0442名無しさん@お腹いっぱい。
2006/11/23(木) 17:01:590443名無しさん@お腹いっぱい。
2006/11/23(木) 17:41:210444名無しさん@お腹いっぱい。
2006/11/23(木) 18:41:14ガンガレ
0445名無しさん@お腹いっぱい。
2006/11/23(木) 19:48:590446名無しさん@お腹いっぱい。
2006/11/23(木) 19:51:570447名無しさん@お腹いっぱい。
2006/11/23(木) 20:02:230448名無しさん@お腹いっぱい。
2006/11/23(木) 20:09:25シリアライズして渡すのかな。ネットワーク越しにも渡せるの?
0449名無しさん@お腹いっぱい。
2006/11/23(木) 20:24:33詳しくはしらんけど
http://www.atmarkit.co.jp/fdotnet/special/powershell02/powershell02_01.html
cmd.exeより100倍ほどつかいやすそうだ。
0450名無しさん@お腹いっぱい。
2006/11/23(木) 20:26:480451名無しさん@お腹いっぱい。
2006/11/23(木) 20:37:550452名無しさん@お腹いっぱい。
2006/11/23(木) 21:59:17判定するにはどうすればいいのでしょうか?
0453名無しさん@お腹いっぱい。
2006/11/23(木) 22:14:56標準出力が、端末か、それ以外(ファイル)かの判定なら、
[ -t 1 ]
でできる。
0455名無しさん@お腹いっぱい。
2006/11/24(金) 10:34:20ちょっとわからないことがあるので質問します。
$ ABC=100
$ VAR=`echo "'\$ABC'"`
$ echo $VAR
$ '100'
(\はバックスラッシュです)
このようになるのですが、実行結果が'$ABC'ではなくて'100'になるのが理解できません。
展開するときに\によって$の効果が打ち消されると思うのですが…。
なぜこうなるかどなたかお教え下さい。お願いします。
0456名無しさん@お腹いっぱい。
2006/11/24(金) 10:38:18VAR=`echo "'\\$ABC'"`
↑
にする必要がある。バッククォートの中の \ は \\ にする。
あと、ここでは結果的に関係ないけど、
最後の echo $VAR は echo "$VAR" にした方がいいな。
0457455
2006/11/24(金) 12:20:02なるほど。$を一つ加えると結果はうまいこといきました。
でもなぜこうなるのかが納得できません。
\\$ABCの部分で一つ目の\が二つ目の\の効果を打ち消して、
$ABCは普通に変数として解釈されechoに渡されると思うのですが…。
それともバッククオートの中では何か特別なルールがあるのでしょうか?
0458名無しさん@お腹いっぱい。
2006/11/24(金) 12:26:12($を加えるんじゃなくて \ を加えるんだけどね)
>バッククオートの中では何か特別なルールがある
と言ってるとおり。
\\$ABC は、バッククォートで1回解釈される時に
\$ABC となってから、その中身が解釈される。
`echo "\\$ABC"`
の中身が解釈される時に
echo "\$ABC"
に変わってから実行されるので。
ちなみに、推奨しないが、バッククォートの代わりに $( )を使うと、
VAR=$(echo "\$ABC")
みたいに、\はひとつで良い。
0459名無しさん@お腹いっぱい。
2006/11/24(金) 12:49:19使える環境では使っとけ。
0460455
2006/11/24(金) 13:15:21ありがとうございました。やっと理解できました。
>>459
$()についても少し調べてみます。使える場合はこっちの方がすっきりしますね。
ご回答いただいた皆様本当にありがとうございました。
0461名無しさん@お腹いっぱい。
2006/11/24(金) 13:16:280462名無しさん@お腹いっぱい。
2006/11/24(金) 13:17:14ってどういう風に解釈されるんですか?
0463名無しさん@お腹いっぱい。
2006/11/24(金) 13:28:13ifconfig_args=AAA
ifn=hoge0
だとすると、
1回目の解釈で、
AAA=$ifconfig_hoge0
になるわな。
で、2回目にifconfig_hoge0の中身がAAAに代入される。
0464名無しさん@お腹いっぱい。
2006/11/24(金) 13:42:06> シェルはポータビリティ大切。
場合によるでしょ。
0465名無しさん@お腹いっぱい。
2006/11/24(金) 14:23:220466名無しさん@お腹いっぱい。
2006/11/24(金) 14:40:40という文字列から 192.168.0.1 の部分を抜き出したいのですが
どのようにすればよいのでしょうか?
0467名無しさん@お腹いっぱい。
2006/11/24(金) 14:46:23スクリプトが読みやすくなるから。
0468名無しさん@お腹いっぱい。
2006/11/24(金) 15:02:08↓を実行。標準入力から hoge.192.168.0.1 の文字列を読ませる。
IFS=. read hoge a b c d
echo $a.$b.$c.$d
>>467
そういう理由は軟弱。却下。
0469名無しさん@お腹いっぱい。
2006/11/24(金) 15:16:230470名無しさん@お腹いっぱい。
2006/11/24(金) 15:20:32???? 「読み易い」って、書き直すってこと?
そもそもポータビリティの意味を誤解してます。
0471名無しさん@お腹いっぱい。
2006/11/24(金) 18:28:430472名無しさん@お腹いっぱい。
2006/11/24(金) 18:37:28伝統的なBourne shellが/bin/shであるような環境では使えない。
Solarisとか。
0473名無しさん@お腹いっぱい。
2006/11/24(金) 20:07:45そのうちSolaris側が /bin/sh -> bash にリンクしてくる可能性すら考えられる。
0474名無しさん@お腹いっぱい。
2006/11/24(金) 21:54:310475名無しさん@お腹いっぱい。
2006/11/24(金) 22:29:240476名無しさん@お腹いっぱい。
2006/11/25(土) 02:19:05------------------------
#!/bin/csh
set i=`ps axwww|grep -i aaaa | grep -v grep | wc -l`
echo $j
------------------------
aaaaは存在しないプロセス。
この実行結果、
「0」でなくて「1」になるのはなぜですか?
0477476
2006/11/25(土) 02:23:46------------------------
#!/bin/csh
set i=`ps axwww|grep -i aaaa | grep -v grep | wc -l`
echo $i
------------------------
0478名無しさん@お腹いっぱい。
2006/11/25(土) 02:41:37パイプで一気に処理している中身を細切れにして中身を確認してみろ。
あと、pgrep があるならそっちを使った方がいい。
0480名無しさん@お腹いっぱい。
2006/11/25(土) 03:22:500481名無しさん@お腹いっぱい。
2006/11/25(土) 19:03:08取得するにはどう記述すればよいのでしょうか?
0482名無しさん@お腹いっぱい。
2006/11/25(土) 19:33:35OSによってifconfigの出力書式が違うかも知れんが、
↓みたいな感じで行ける。
ifconfig -a | sed -n 's/^\([^ ][^ ]*\).*/\1/p'
0483名無しさん@お腹いっぱい。
2006/11/25(土) 19:37:28lanscanだな。
0484名無しさん@お腹いっぱい。
2006/11/25(土) 20:30:330485名無しさん@お腹いっぱい。
2006/11/25(土) 21:05:380486名無しさん@お腹いっぱい。
2006/11/26(日) 14:56:47ミスプリ程度の間違いじゃない、ダメ本みたいだ。
こっちの書き込みによると。
↓
http://pc8.2ch.net/test/read.cgi/linux/1065059126/794
0487名無しさん@お腹いっぱい。
2006/11/27(月) 02:12:37クォートされずに*が展開されて位置パラメタに入っちゃうんだけどなんでなんでだろ。
echoとかの組み込みコマンドだと上手くクォートされるんだけどなぁ。
0488名無しさん@お腹いっぱい。
2006/11/27(月) 07:20:57どこかでクォートし忘れているって事なんだろうな。
そのスクリプトを晒してみな
0489名無しさん@お腹いっぱい。
2006/11/29(水) 21:31:140490名無しさん@お腹いっぱい。
2006/11/29(水) 21:52:550491名無しさん@お腹いっぱい。
2006/11/29(水) 22:31:42それは csh。cshは帰れ。
/bin/shでは set -f
ただし、ちゃんとクォートすれば set -f は必要ない。
0492名無しさん@お腹いっぱい。
2006/11/30(木) 21:22:530493名無しさん@お腹いっぱい。
2006/11/30(木) 21:28:40Bourne Shellでは $10以降は使えない。
bashとかkshとかでは使えるが、${10} とする必要あり。
zshでは $10 でも使える。
0494名無しさん@お腹いっぱい。
2006/11/30(木) 21:31:31${1}0と解釈されるから、${10}としないとだめ。
0495名無しさん@お腹いっぱい。
2006/11/30(木) 21:33:030496名無しさん@お腹いっぱい。
2006/11/30(木) 21:33:29Bourne Shell では ${10} でもダメ。逆に zsh では $10 でも桶。
0497492
2006/12/01(金) 00:40:19shで最後の引数を取得したかったのですが、無理なのですね。
0498名無しさん@お腹いっぱい。
2006/12/01(金) 00:48:110499名無しさん@お腹いっぱい。
2006/12/01(金) 02:24:15"Portable Shell:: Shell script portability pitfalls"
が非常に詳しくて面白い。よくこれだけまとめあげたものだ
■ このスレッドは過去ログ倉庫に格納されています