シェルスクリプト総合 その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 でトレースしましょう。
0062名無しさん@お腹いっぱい。
2006/09/15(金) 08:02:35もしくはそれを決めないと、何とも言えん。
0063名無しさん@お腹いっぱい。
2006/09/15(金) 08:30:21awk使っていいなら簡単じゃん。
awk '
/^開始1/,/^終了1/{ print > "data1.txt" }
/^開始2/,/^終了2/{ print > "data2.txt" }
/^開始3/,/^終了3/{ print > "data3.txt" }
' data.txt
0064名無しさん@お腹いっぱい。
2006/09/15(金) 09:14:54ファイルの名称は重複さえしなければ、どんな名称でも構いません。
見つかった順に 0001.txt, 0002.txt,...のような形でも構いませんし、ラン
ダムに生成した名称でも構いません。
>>63
あっ ごめんなさい。
ファイル中に複数存在するブロックというのが、数百のオーダーで存在してい
ます。
また、区切り文字列は全て同じもの(今回の例では「開始」〜「終了」)です。
0065名無しさん@お腹いっぱい。
2006/09/15(金) 09:39:15シェルスクリプトと直接関係ないし。
0066名無しさん@お腹いっぱい。
2006/09/15(金) 09:46:50簡単じゃん。
↓
awk '
BEGIN { n=0 }
/^開始/{ n++ }
/^開始/,/^終了/{ print > n ".txt" }
' data.txt
0067名無しさん@お腹いっぱい。
2006/09/15(金) 10:15:44情報を小出しにするつもりはなかったのですが、結果
としてそうなってしまいました。
書き込む前にもうちょっと冷静に読み返すべきでした。
ごめんなさい。
>>66
ありがとうございます。
ご教示頂いた方法で希望通りの処理を実現できました。
0068名無しさん@お腹いっぱい。
2006/09/15(金) 10:39:57csplitも使えるかな。
0069名無しさん@お腹いっぱい。
2006/09/15(金) 15:26:51find は大丈夫そうだけど
[root@cis_svr_p]# find . -name *bb* -exec ls -l {} \;
-rw-r--r-- 1 root system 0 Sep 15 15:16 ./xx/aa bb
-rw-r--r-- 1 root system 0 Sep 15 15:17 ./xx/aa bb dd
-rw-r--r-- 1 root system 0 Sep 15 15:17 ./xx/ aa bb dd
xargs はないと困りそうだね。
15年以上UNIXシステムに携わってるけどブランク入りファイルが
メンテナンスの対象になるシステムは見たことないや。
学校系に多いのかな。
0070名無しさん@お腹いっぱい。
2006/09/15(金) 15:30:15だから Sambaサーバーって言ってるだろ。
スペース入りのファイルなんて日常茶飯事的にユーザーが作るよ。
0071名無しさん@お腹いっぱい。
2006/09/15(金) 15:47:00Windows でかためた方が楽じゃん。
0072名無しさん@お腹いっぱい。
2006/09/15(金) 15:59:32UNIXユーザーでも普通にスペース入りのファイル名作るよ。
0073名無しさん@お腹いっぱい。
2006/09/15(金) 17:36:430074名無しさん@お腹いっぱい。
2006/09/15(金) 20:02:00ちなみにユーザーが作ったファイルを
find やら xargs で何するの?
0075名無しさん@お腹いっぱい。
2006/09/15(金) 20:05:31チェックするんじゃないか。
0076名無しさん@お腹いっぱい。
2006/09/15(金) 20:26:060077名無しさん@お腹いっぱい。
2006/09/15(金) 21:31:280078名無しさん@お腹いっぱい。
2006/09/15(金) 21:44:380079名無しさん@お腹いっぱい。
2006/09/16(土) 00:05:520080名無しさん@お腹いっぱい。
2006/09/16(土) 08:23:03find ... -print0 | xargs -0 が使えない環境では、xargsを使わず、
find ... -exec ... で個別に -exec するのが正しい。(プロセスが無駄でも)
0081名無しさん@お腹いっぱい。
2006/09/16(土) 17:59:11-print0がつかえず、かつファイル数が多すぎるときは?
0082名無しさん@お腹いっぱい。
2006/09/16(土) 18:00:30GNU findutilsを入れる。
0083名無しさん@お腹いっぱい。
2006/09/26(火) 21:09:460084名無しさん@お腹いっぱい。
2006/09/26(火) 21:51:530085名無しさん@お腹いっぱい。
2006/10/04(水) 16:47:35それをシェルで一括で変換したいんです。
echo ########## | awk '{print strftime("%c",$1)}' >tempuni.txt
みたいな感じで
どのようにやればいいでしょうか?
お願いします
0086名無しさん@お腹いっぱい。
2006/10/04(水) 16:53:54イマイチ仕様が不明確だが、
$ echo 1157601611 | date -d "1970-01-01 `cat` seconds"
Thu Sep 7 04:00:11 JST 2006
↑みたいにできればいいのかな?
タイムゾーンは別途考慮のこと。
では、後出しの仕様どうぞ
↓
0087名無しさん@お腹いっぱい。
2006/10/04(水) 16:56:150088名無しさん@お腹いっぱい。
2006/10/04(水) 16:59:210089名無しさん@お腹いっぱい。
2006/10/04(水) 17:00:150090名無しさん@お腹いっぱい。
2006/10/04(水) 17:01:41そんな感じです。
それをファイルの中のUNIXTIMEを1行目から500行目まで一括で変換したい。
1157601611
1157601612
1157601613
1157601614
・
・
・
みたいにならんでます
>>87
すいません。コマンドでした。
でもシェルでも出来ると思って・・・。
0091名無しさん@お腹いっぱい。
2006/10/04(水) 17:05:17じゃあ、hoge.txt に
1157601611
1157601612
1157601613
1157601614
が書かれてるとして、
以下を実行
↓
for t in `cat hoge.txt`
do
date -d "1970-01-01 09:00 $t seconds"
done
0092名無しさん@お腹いっぱい。
2006/10/04(水) 17:12:32ありがとう御座います。
temp.txtに書き出しながら処理するにはどうしたら良いですか?
0093名無しさん@お腹いっぱい。
2006/10/04(水) 17:15:11done の行を
done > temp.txt
にすればいいだろ。ただのリダイレクトだよ。
0094名無しさん@お腹いっぱい。
2006/10/04(水) 17:17:41何を質問したいのか意味不明。
>>85 のやりかたでやるなら、
awk '{print strftime("%c",$1)}' > tempuni.txt < hoge.txt
で桶。
もしかして、単に入力ファイルのリダイレクト方法を知らなかっただけ?
0095名無しさん@お腹いっぱい。
2006/10/04(水) 18:40:49CSVファイルの特定のフィールドの日付を書き換えなきゃなりません。
たとえば三番目のフィールドを199912から200001のように全行書き換える
にはどうしたらいいのでしょうか。
日付計算は終わってます。${B_YEAR}${B_MONTH} →${A_YEAR}${A_MONTH}
に入れ替えたいのですがsed使ってもなかなかうまくいきません。
awkで特定のフィールドを表示する方法ならわかるのですが、特定のフィールド
を置き換えた上で他のフィールドをそのまま表示する方法がわかりません。
0096名無しさん@お腹いっぱい。
2006/10/04(水) 18:54:49厳密な仕様をください。""中の"や,の扱いとか。
0097名無しさん@お腹いっぱい。
2006/10/04(水) 19:59:49date -f hoge.txtは使えないのかなあ
0098名無しさん@お腹いっぱい。
2006/10/04(水) 20:07:02date -f は、UNIX時間の形式(ただの数字)には対応してない。
(やってみればわかるが)
なので、>>91 で正解。
0099名無しさん@お腹いっぱい。
2006/10/04(水) 20:27:02cat hoge.txt |sed -e "s/.*/1970-01-01 & second/;" |date -f -
で出来た
0100名無しさん@お腹いっぱい。
2006/10/04(水) 20:37:30お約束の突っ込み。「catが無駄です」
0101名無しさん@お腹いっぱい。
2006/10/04(水) 20:38:07""はないです。
YYYYMM,HOGE,0,YYYYMM,YYYYMM,------中略-------,YYYYYMM,0,0,0,0
のような感じで日付が何箇所あります。現時点では各日付の関係
がわかりません。 m(_ _)m
0102名無しさん@お腹いっぱい。
2006/10/04(水) 20:39:40いや、わざわざ sed 通すくらいなら >>94 でいいだろ。1プロセスで済むし。
0103名無しさん@お腹いっぱい。
2006/10/04(水) 20:48:16manにdate起動のオーバーヘッド云々って書いてある。
0104名無しさん@お腹いっぱい。
2006/10/04(水) 20:51:48欲嫁。>>94 って言ってるんだよ。dateなんて1度も起動しないよ。
0105名無しさん@お腹いっぱい。
2006/10/04(水) 22:15:560106名無しさん@お腹いっぱい。
2006/10/05(木) 01:02:04WINDOWS上でシェルスクリプト動作確認をする方法はありますか?
0107名無しさん@お腹いっぱい。
2006/10/05(木) 01:13:36cygwin
0108名無しさん@お腹いっぱい。
2006/10/05(木) 01:28:44バカくせぇ
0109名無しさん@お腹いっぱい。
2006/10/05(木) 13:16:35cutやpasteコマンドを使うところなのかもしれないし、
シェルスクリプトとは言い難いが
perl -apF, -e '$, = ","; $/ = "\n"; splice(@F, $n, 1, $F[$n]を加工); print @F' < csvファイル
で出来ない?
0110名無しさん@お腹いっぱい。
2006/10/05(木) 13:17:050111名無しさん@お腹いっぱい。
2006/10/05(木) 23:37:13GNU sed を使うという手もある。
例)
$ echo 'abcdef' | sed 's/a\(b\)c\(de\)f/x\1y\2z/'
xbydez
0112名無しさん@お腹いっぱい。
2006/10/07(土) 03:06:18Solaris環境で自分で勝手にはgnu sed使えないのですが
perlは入っているので試してみます。∩(´∀`)∩ワァイ♪
0113名無しさん@お腹いっぱい。
2006/10/07(土) 10:54:57Windowsで使う下記のような内容のバッチファイルを作るために、
Solaris8上で簡単なスクリプトを作成しますた。
<バッチファイルの中身 (期待している実行結果)>
lha32 a D:\save\0.lzh D:\work\0\
lha32 a D:\save\1.lzh D:\work\1\
lha32 a D:\save\2.lzh D:\work\2\
:
lha32 a D:\save\9999.lzh D:\work\9999\ (←9999部分は、実際は第1引数で指定)
<作ったスクリプト>
#!/bin/sh
COUNT=0
LAST=$1
while [ $COUNT -le $LAST ]
do
echo "lha32 a D:\\save\\$COUNT.lzh D:\\work\\$COUNT\\"
COUNT=`expr $COUNT + 1`
done
0114続き
2006/10/07(土) 10:55:420の値が消えてしまう現象が出てしまいまつ。(´・ω・`)
<shの実行結果>
lha32 a D:\save.lzh D:\work ←0が消えている
lha32 a D:\save\1.lzh D:\work\1\
lha32 a D:\save\2.lzh D:\work\2\
:
試しにシェルの種類を変えてみたところ、ksh, zsh は sh と同じ挙動を示し、
bashのみ期待していた出力となりますた。
<bashの実行結果>
lha32 a D:\save\0.lzh D:\work\0\
lha32 a D:\save\1.lzh D:\work\1\
lha32 a D:\save\2.lzh D:\work\2\
:
この現象について、
・何故、0が消えるのか?
・/bin/shを使った場合に0を表示させる方法
について教えてください。
おまいら、よろしくおながいします。
0115名無しさん@お腹いっぱい。
2006/10/07(土) 11:39:340116名無しさん@お腹いっぱい。
2006/10/07(土) 11:50:42それは、echoコマンドの仕様が違うため。
Solarisなどの /bin/sh の echo は、bashの echo -e に相当する。
echo -e 相当だと、\ が、シェルと echoで2回解釈されるので、
単純な \ を出力させたければ、\\\\ と書かないと行けない。
よって↓で桶。
echo "lha32 a D:\\\\save\\\\$COUNT.lzh D:\\\\work\\\\$COUNT\\\\"
0118名無しさん@お腹いっぱい。
2006/10/07(土) 12:10:55echo "lha32 a D:\\save\\\\$COUNT.lzh D:\\work\\\\$COUNT\\"
でもいいな。
0119名無しさん@お腹いっぱい。
2006/10/07(土) 12:42:08ashとかだと、\1 でも 8進数の1と解釈するから、それはお勧めできない。
すべて \\\\ にするのが吉。
0120名無しさん@お腹いっぱい。
2006/10/07(土) 13:00:20echo時は無難な/にでもしといて |sed とかしてまとめてエスケープつけると
見やすいかも。好きずきだが。
0121名無しさん@お腹いっぱい。
2006/10/07(土) 13:02:25んな中途半端なもん使うなや
それに\1になりうるのは\\$COUNTのところだけだろ。
0122名無しさん@お腹いっぱい。
2006/10/07(土) 13:22:46D:\\tave とかだったら困るだろ。
\\\\ にしとけ。
0123名無しさん@お腹いっぱい。
2006/10/07(土) 13:24:36ディレクトリ区切りは/としておいて、最後に一括変換すればよい。
#!/bin/sh
COUNT=0
LAST=$1
while [ $COUNT -le $LAST ]
do
echo "lha32 a D:/save/$COUNT.lzh D:/work/$COUNT/"
COUNT=`expr $COUNT + 1`
done | tr '/' '\\'
0124名無しさん@お腹いっぱい。
2006/10/07(土) 13:38:18んな中途半端なもん使うなや
0125名無しさん@お腹いっぱい。
2006/10/07(土) 19:02:19というかむしろ変数展開部分だけ"〜"使え。ややこしいときは。
echo lha32 a 'd:\\save\\'"$COUNT.lzh" 'd:\\work\\'"$COUNT"'\\'
0126名無しさん@お腹いっぱい。
2006/10/07(土) 20:28:15printf があるのに、エスケープシーケンスを解釈してしまうようなままにしとくのがいけない。
バッドノウハウの典型だな。
0127名無しさん@お腹いっぱい。
2006/10/07(土) 20:32:360128名無しさん@お腹いっぱい。
2006/10/07(土) 22:39:17んで、echoがエスケープシーケンスをデフォルトで解釈するビルドもできちゃう
どっちつかずなbashがGJなのかよw
0129名無しさん@お腹いっぱい。
2006/10/08(日) 00:09:400130名無しさん@お腹いっぱい。
2006/10/08(日) 01:13:220131名無しさん@お腹いっぱい。
2006/10/08(日) 06:43:25Solarisなどのecho(/bin/echoも含む)が、エスケープシーケンスを無効にする方法がないことをいってるんジャマイカン?
013295-101
2006/10/10(火) 14:04:36/usr/bin/sed /usr/ucb/sed /usr/xpg4/bin/sed でも動作しました。
0133名無しさん@お腹いっぱい。
2006/10/16(月) 01:05:51特定拡張子のファイルを一括処理しょうと思い、
for file in `find . -name "*.hoge"`
do
のようにやると、スペースごとに変数fileに入ってしまうのだが
簡単な回避方法ありますか?
0134名無しさん@お腹いっぱい。
2006/10/16(月) 01:25:320135名無しさん@お腹いっぱい。
2006/10/16(月) 01:40:44ありがと。勉強になりました。
while 使えば行処理できたのか〜。
0136名無しさん@お腹いっぱい。
2006/10/16(月) 03:24:33find ... -print0 | xargs -0
もあり。
0137名無しさん@お腹いっぱい。
2006/10/17(火) 17:36:58aaa
bbb
ccc
ddd
eee
fff
といった文字列(6行)が入っている。
変数$2222には
bbb
ccc
といった文字列(2行)が入っている。
$2222の中身を、「1行ずつ」grepキーワードとして、
cat $1111 | grep bbb
cat $1111 | grep ccc
と個別にcatを実行したい。
どうしればいいだろう。
0138名無しさん@お腹いっぱい。
2006/10/17(火) 17:41:220139名無しさん@お腹いっぱい。
2006/10/17(火) 17:47:04$2222 って、2,222個目の引数のことだぞ。普通のシェル変数じゃない。
で、勝手に $hoge1 $hoge2 と置き換えさせてもらうが、答えは echoを使うこと。
echo "$hoge1" | grep bbb
echo "$hoge2" | grep ccc
ダブルクォート " " で囲むのが重要。
0140名無しさん@お腹いっぱい。
2006/10/17(火) 17:47:430141名無しさん@お腹いっぱい。
2006/10/17(火) 17:49:360142名無しさん@お腹いっぱい。
2006/10/17(火) 18:21:590143名無しさん@お腹いっぱい。
2006/10/17(火) 18:30:25後付けで問題訂正されるより、 >>137 がもう一度正確な問題を書くまで待機した方が良さそう。
0144名無しさん@お腹いっぱい。
2006/10/17(火) 18:33:44↓
for keyword in $hoge2
do
echo "$hoge1" | grep "$keyword"
done
$hoge2のところは " " なし(←これ重要)
$hoge1のところは " " あり(←これ重要)
0145名無しさん@お腹いっぱい。
2006/10/17(火) 18:38:150146名無しさん@お腹いっぱい。
2006/10/17(火) 18:39:32だから、catだと勘違いしてる >>137 の問題が間違いだろ。
0147名無しさん@お腹いっぱい。
2006/10/17(火) 18:41:20勘違いかどうかわかんないじゃん。
決めつけはよくないよ。
0148名無しさん@お腹いっぱい。
2006/10/17(火) 18:43:56オマエアフォだな。もし catだと、
aaa
bbb
ccc
ddd
eee
fff
という改行付き6行もある変態的なファイル名のファイルを読み込むことになるんだよ。
echoの間違いだとエスパーしてあげたのは親切と言えよう。
0149名無しさん@お腹いっぱい。
2006/10/17(火) 18:45:200150名無しさん@お腹いっぱい。
2006/10/17(火) 18:48:00↓こういうことか?
for file in $hoge1
do
for key in $hoge2
do
grep "$key" < "$file"
done
done
0151名無しさん@お腹いっぱい。
2006/10/17(火) 18:50:42変態的なファイル名の可能性もあるし、
複数のファイル名が変数に格納されてるのかもしれない。
勝手な解釈しちゃいかんよ。
0152名無しさん@お腹いっぱい。
2006/10/17(火) 18:54:55変数 $1111 改め $hoge1 の内容はファイル名じゃなく、文字列そのものだろ。
>>144 のエスパー(echo)が正しいに1票。
>>150 だと、「変数 $1111には1行ずつファイル名が入ってます」とかいう表現になるはず。
0153名無しさん@お腹いっぱい。
2006/10/17(火) 18:58:04その可能性もあるけど、あくまで可能性。
そこは本人に言わせなきゃだめだよ。
0154名無しさん@お腹いっぱい。
2006/10/17(火) 19:02:180ポイントのけいけんちかくとく
0155137
2006/10/17(火) 22:47:25あ、そうだった。1111番目のひき数って意味ではなく、ご認識の通り。
catはファイル名対象が前提なんですね。
スクリプト内での処理ですので、echoのことです。訂正します。
>>144氏ので行けそうな気がする。ありがとうございます>各位
今回は"ファイル名"というものは存在しません。
0156137
2006/10/17(火) 22:59:57というか、変な質問してしまったことに今気がついた。
迷惑かけた。
今日8時間ぐらいずっとそれで悩んでたんだ。
googleで調べるとreadって命令を見つけたのでずっとそれと格闘してた。
0157名無しさん@お腹いっぱい。
2006/10/18(水) 10:08:51>$hoge1のところは " " あり(←これ重要)
これなんで?
あっても無くても同じじゃないの?
0158名無しさん@お腹いっぱい。
2006/10/18(水) 10:13:48word splittingが行われるので違ってくるんだな。
0159名無しさん@お腹いっぱい。
2006/10/18(水) 10:14:100160名無しさん@お腹いっぱい。
2006/10/18(水) 10:14:37do
echo "$hoge1" | grep "$keyword"
echo TEST
done
別人だけど、これを実行しても
aaa
bbb
ccc
ddd
eee
fff
TEST
と表示されてしまうぞ。
bbb
TEST
ccc
TEST
とならなってくれないとおかしいのでは。
0161157
2006/10/18(水) 10:17:06echo $hoge1
としたのでは、
下手すると
$hoge
という文字列そのものが表示されてしまう恐れがあるってことかな。
■ このスレッドは過去ログ倉庫に格納されています