シェルスクリプト総合 その16
■ このスレッドは過去ログ倉庫に格納されています
0001名無しさん@お腹いっぱい。
2010/02/20(土) 14:10:05スクリプトのお勉強・自慢・腕試しなどにどうぞ。
まずは注意点、リンク、地鎮祭など(>>1-6くらい)をご覧ください。
□お約束
・特記なき場合はBourne Shell(/bin/sh)がデフォルトです。
bash/zsh/ksh/ashなどに依存する場合は明示しましょう。
Linuxユーザは/bin/shの正体がbashなので特に注意。
FreeBSDユーザは/bin/shの正体がashなので注意。
v7 shに一番近くて、現役のshは、OpenSolaris由来のheirloom sh。
http://src.opensolaris.org/source/xref/onnv/onnv-gate/usr/src/cmd/sh/
http://heirloom.sourceforge.net/sh.html
・csh/tcshのシェルスクリプトは推奨されません。
(理由は「csh-whynot」でググれ)
・UNIXにはシェルスクリプトに便利な小さなコマンドがいろいろあります。
manや参考リンクを見ましょう。
aproposないしはman -kでそれらしい単語による簡単な検索もできます。
・シェルスクリプトのことをシェルってゆーな
・シェルで使えるワイルドカード等は正規表現ではありません。
正規表現の話題はスレ違い(正規表現スレへ)
□初心者へのアドバイス:
・適した道具を判断するのも頭の重要な使い方。シェルスクリプトよりも
RubyやPerlの方が適した仕事には素直にそちらを使いましょう。
・知らないコマンドが出てきたらmanを引きましょう。
・思い通りに動かないときは、まずは sh -x でトレースしましょう。
前スレ
シェルスクリプト総合 その15
http://pc12.2ch.net/test/read.cgi/unix/1246408968/l50
0500名無しさん@お腹いっぱい。
2010/06/27(日) 01:29:20awk '{print $1}' とかで切り出せば余分な空白は無くなる。
0501名無しさん@お腹いっぱい。
2010/06/27(日) 01:57:41EQ
0502名無しさん@お腹いっぱい。
2010/06/27(日) 08:45:20GNU wc は、wc -l とか wc -c とかの時、余分な行頭スペースは入らない。
0503名無しさん@お腹いっぱい。
2010/06/27(日) 09:17:16awkなんか使わなくても、
[ `wc -l < file` -eq 123 ]
でいいだろ。
"`wc -l .. `" じゃなくて単に `wc -l ...` にする。
>>501
シェル依存。
$ test ' 0' -eq 0 && echo EQ
test: 0: bad number
0504名無しさん@お腹いっぱい。
2010/06/27(日) 18:16:27bashでテキストファイルで空欄があるところを改行に変換するシェルスクリプトを作りたいんですが
どうすればよいでしょうか?
0505名無しさん@お腹いっぱい。
2010/06/27(日) 19:18:380506名無しさん@お腹いっぱい。
2010/06/27(日) 19:26:54man tr
0507名無しさん@お腹いっぱい。
2010/06/27(日) 19:57:24man tr < file.txt
ってやってみましたが、動作が変です。
0508名無しさん@お腹いっぱい。
2010/06/27(日) 20:23:380509名無しさん@お腹いっぱい。
2010/06/27(日) 20:25:31↓
----
#!/bin/bash
いいから man tr < file.txt
----
0510名無しさん@お腹いっぱい。
2010/06/27(日) 20:34:580511名無しさん@お腹いっぱい。
2010/06/27(日) 23:28:390513名無しさん@お腹いっぱい。
2010/07/27(火) 03:09:25#!/bin/bash
hostname
$hostname = `hostname`
echo $hostname
上記のシェルスクリプトを実行すると
hostnameだけの行はしっかり標準出力にホスト名が表示されるのですが、
$hostname = `hostname`で command not foundと怒られてしまいます。
なぜでしょうか・・・?
0514名無しさん@お腹いっぱい。
2010/07/27(火) 03:19:29#!/bin/bash
hostname
hostname = `hostname`
echo $hostname
でした。結果が
=
とだけ表示されてしまいます。標準出力の結果が変数に入っていないのでしょうか
0515名無しさん@お腹いっぱい。
2010/07/27(火) 03:23:090516名無しさん@お腹いっぱい。
2010/07/27(火) 03:27:38ありがとうございます。解決しました。
いろいろやってたら、間違ってhostnameに=を設定してしまっていたことも重なっておりました。
0517名無しさん@お腹いっぱい。
2010/07/27(火) 13:02:180518名無しさん@お腹いっぱい。
2010/07/28(水) 21:03:26マルチコアの上で動かすときに重宝しています。
しかし、例えば
for i in *.jpeg
do
convert $i `basename $i .jpeg`.png
done
のような多少複雑な操作をxargs -Pのような形で簡単に並列実行することはできるでしょうか?
"args"だけでなくてリダイレクトにも使用できることを望んでいます。
# 普段はzsh使ってるので for i in *.jpeg; convert $i $i:r.png とか書いてますが
zargsのような、zshに依存するやり方でも構いません。
ご存知でしたら教えていただければ幸いです。
0519名無しさん@お腹いっぱい。
2010/07/28(水) 21:09:45単純にバックグラウンドで、
for i in *.jpeg
do
convert $i `basename $i .jpeg`.png &
done
wait
でいいんじゃないの。
それよりスペースや特殊記号入りファイル名の対応の方が気になる。
0520名無しさん@お腹いっぱい。
2010/07/28(水) 21:28:090521名無しさん@お腹いっぱい。
2010/07/28(水) 21:42:38ありがとうございます。
変換する元のファイルも基本的に自分で作成するつもりなので、
ファイル名は「行儀のいい」ものと仮定して、スペースや特殊記号は特に意識していませんでした。
その代わり、ファイル数は100?のオーダーを考えているので、
バックグラウンドに全部一気に詰め込むのではなく、
最大並列プロセス数を与えて、その数だけ常に動かしつづけてくれる仕組みが欲しいのです。
0522名無しさん@お腹いっぱい。
2010/07/28(水) 21:43:44すみません、文字化けしてます。
×ファイル数は100?のオーダー
○、ファイル数は100 - 10000のオーダー
です。
0523518
2010/07/29(木) 13:56:52zsh依存ですが、例えば
function jpeg2png(); convert $1 $1:r.png
zargs -P4 -n1 -- $(echo *.jpeg|sed -e 's/ /\n/g') -- jpeg2png
とか。
ワンライナーで書きたかったのですが、これ以上にいいやり方ありますかね。
あと、$()の中が若干不細工ですが。
0524名無しさん@お腹いっぱい。
2010/07/31(土) 10:29:17複数文字のオプションの処理はどのようにやるのが一般的なのでしょうか?
0525名無しさん@お腹いっぱい。
2010/07/31(土) 11:28:10プログラムで質問があります。
/hoge/test/
の中に
1filename1.gif
1filename2.gif
2filename1.gif
2filename2.gif
があるとします。
# sh /hoge/test/*filename*
という感じにコマンドを入力すると
それらの複数のファイルが
command /hoge/test/1filename1.gif -option /aaa/bbb/1filename1.jpg
command /hoge/test/1filename2.gif -option /aaa/bbb/1filename2.jpg
command /hoge/test/2filename1.gif -option /aaa/bbb/2filename1.jpg
command /hoge/test/2filename2.gif -option /aaa/bbb/2filename2.jpg
って感じにファイルが無くなるまで全て、コマンドを実行したいのですが
どうすればいいのでしょうか??
0526名無しさん@お腹いっぱい。
2010/07/31(土) 11:36:52for f in "$@"
do
echo command "$f" -option "${f%%.gif}".jpg
done
0527524
2010/07/31(土) 12:29:250528名無しさん@お腹いっぱい。
2010/07/31(土) 12:51:270529名無しさん@お腹いっぱい。
2010/07/31(土) 14:03:440530名無しさん@お腹いっぱい。
2010/07/31(土) 14:07:360531524
2010/07/31(土) 14:39:07これって常識でしたか(笑)。
0532名無しさん@お腹いっぱい。
2010/07/31(土) 14:42:340533524
2010/07/31(土) 14:48:53それと$@なんかは"で囲う必要あり。
0534名無しさん@お腹いっぱい。
2010/07/31(土) 14:52:31Arguments containing white space or embedded shell metacharacters
generally will not survive intact; this looks easy to fix but is not.
0535名無しさん@お腹いっぱい。
2010/08/08(日) 20:39:19リスト化したファイルを読み込んでfind検索の後、圧縮かけて削除
処理させるスクリプト書いているのですが、どう書いて良いのか??
1)/home/hoge配下に、sample.lstと言うファイルを作成
2)(1)のリストを読み込んで、最終アクセスが7日経過しているファイルを検索
3)(2)に該当したものを圧縮して、元ファイルを削除する。
/*リスト化ファイル内*/
/home/aaa/abc
/home/bbb/abc
/* バックアップスクリプト*/
#!/bin/sh
BACKUPLIST=/home/hoge/sample.lst
FIND=`find $BACKUPLIST -type f -daystart -atime +7 `
tar cvzf `date +%Y%m%d`.tar.gz $TARGET && rm $TARGET
もちろん、上記では色々と問題がありますがこう言う風な処理をしたいと。
http://centossrv.com/backup.shtml ここの処理に、find検索の処理を追加
出来れば解決なのですが・・・。
0536名無しさん@お腹いっぱい。
2010/08/08(日) 20:40:39FIND=`find $BACKUPLIST -type f -daystart -atime +7 `
tar cvzf `date +%Y%m%d`.tar.gz $FIND && rm $FIND
でした。
0537名無しさん@お腹いっぱい。
2010/08/08(日) 20:57:36find [パス] [検索条件] -exec tar -czf $(date +%Y%m%d).tar.gz {} + -delete -print
0538名無しさん@お腹いっぱい。
2010/08/08(日) 21:06:51rやuじゃなくcで作ってるとはじめのほうのは失われてしまわないかね?
0539名無しさん@お腹いっぱい。
2010/08/08(日) 21:14:59ごめん、全然ダメだった
>>537実行すると超危険なので実行しないで!
まじでゴメン><
0540>>535-536
2010/08/08(日) 21:17:11アドバイス有難う。
でも、パスにfind $BACKUPLIST ・・・と書くとリストのパスを参照して
中身を参照検索してくれない。
単純にパスを指定すれば、うまくいくのだが???
find /home/aaa/abc ・・・で
>>538
findの所はループ処理だ回さないと駄目なのでしょうかね??
>>539
危ない、まだ実行していないので大丈夫wwww
0541名無しさん@お腹いっぱい。
2010/08/08(日) 21:39:25find /home/hoge/sample.lst ...が実行されちゃう
find $(< $BACKUPLIST) ...しないとダメだね
0542>>535-536
2010/08/08(日) 21:52:07レス有難う。
試しに、実行させたらとりあえず動いたんだが
tarの処理でエラーが出た・・・。
tar: 処理中にエラーが起きましたが、最後まで処理してからエラー終了させました
一応、圧縮は出来ているようだけど。
後、可能であればで良いのですが圧縮元を/home配下からではなく
abcフォルダ配下から圧縮出来ればベストなのですが。
一旦cdで/home/abcフォルダに移動しないとやっぱり駄目なのかな??
0543>>535
2010/08/08(日) 22:09:46#!/bin/sh
BACKUPLIST=/home/genki/backup/sample.lst
FIND=`find $(<$BACKUPLIST) -type f -daystart -atime +7`
tar cvzf `date +%Y%m%d`.tar.gz $FIND && rm $FIND
tarの際、全角ペースが入っているファイルがエラーになってバックアップ
取れなかった以外は、ほぼ思っている処理が出来ました。
tar: ドキュメント.txt: stat 不能: そのようなファイルやディレクトリはありません
tar: 処理中にエラーが起きましたが、最後まで処理してからエラー終了させました
本来なら、新規 ドキュメント.txt と言うファイルがあるのだけど・・・。
0544名無しさん@お腹いっぱい。
2010/08/08(日) 22:10:40BACKUPLIST=/home/hoge/backup/sample.lst
0545名無しさん@お腹いっぱい。
2010/08/08(日) 22:18:49えっと、リストは絶対に必要なのかな?
スクリプト内に書いとくのでは駄目なのか
ファイルから読み込むとなると、どうしてもループさせることになるので色々と困るのだが…
>>543のように空白含むパス名の扱いにも問題が出る
BACKUPLIST内のディレクトリの数が数千とかじゃなければスクリプト内に書いたほうが楽
/home/abcってのはちょっとよく分からない
>>535では/home/aaa/abc、/home/bbb/abcの2つのディレクトリがあるようだけど
アーカイブを2つ作りたいってことなのかな
0546>>543
2010/08/08(日) 22:42:51なるべく、リスト内で処理したいです。
理由は、数千もディレクトリは無いにしろ数十・数百あるとかなり厳しいです。
後、スクリプト内を簡潔にしたいのもあります。
でも、>>545の言う通り数十・数百位のディレクトリならスクリプト内に
書いた方が楽なら、そちらの方がベスト!?なのかも・・・・。
確かに、両方abcとあるので分かりにくいので/home/aaa/test1と/home/bbb/test2
なら大丈夫ですかね??
/home/aaa/test1配下と/home/bbb/test2配下にあるものを1つのアーカイブで
まとめたいって事です。
0547名無しさん@お腹いっぱい。
2010/08/08(日) 22:50:31#!/bin/bash
# ${HOME}以下の相対パスを書く
l=("foo bar/" "hoge fuga/")
cd ~
mkfifo tmp.fifo
find "${l[@]}" -type f -daystart -atime '+7' \
-exec tar -cvzf $(date +%Y%m%d).tar.gz {} + -fprintf tmp.fifo '%P\n' &
while read f; do rm -f "${f}"; done <tmp.fifo
rm tmp.fifo
本当は素直にfindを2回かけて-exec tar、-deleteすればいいんだけど
条件に-atimeが入ってるので1回目と2回目のfindの結果が変わっちゃう
(findではatimeは変わらないけどtarすると変わるらしい)
なのでnamedpipeを作ってrmをwhileで回すという面倒臭いことをしてる
削除するファイルが増えればそれなりに遅くなるはず
誰かもっと良いやり方あれば教えてください
find一発で出来ないものか
0548名無しさん@お腹いっぱい。
2010/08/08(日) 23:04:24それじゃあ、ひと手間増えるけど
#!/bin/bash
backuplistfile="${HOME}/backuplist"
fifo="/tmp/backup.fifo"
while read p; do backuplist=("${backuplist[@]}" "${p}"); done <"${backuplistfile}"
cd /home
mkfifo "${fifo}"
find "${backuplist[@]}" -type f -exec tar -cvzf testbackup.tar.gz {} + -fprintf "${fifo}" '%P\n' &
while read f; do echo rm -f "${f}"; done <"${fifo}"
rm "${fifo}"
で、backuplistにはaaa/test1等と書いておけばいい
面倒だなぁ…俺てっきり>>537で行けると思ったのに
0549>>546
2010/08/08(日) 23:06:18スクリプトthx
とりあえず、なにかベストなやり方をもう少しググってみます。
他にもっとベストなやり方があればアドバイスよろしくお願いします。
0550名無しさん@お腹いっぱい。
2010/08/08(日) 23:09:52同じくスクリプトthxです。
明日ちょっと、実行させてみます。
結果はまた報告します。
0551名無しさん@お腹いっぱい。
2010/08/08(日) 23:10:520552名無しさん@お腹いっぱい。
2010/08/09(月) 14:34:410553名無しさん@お腹いっぱい。
2010/08/09(月) 14:52:50マジでっ!?
0554名無しさん@お腹いっぱい。
2010/08/09(月) 17:37:58ループから脱出(break;) したり、次の周回に飛ぶ(continue;) には、
どうするのがよいのでしょうか。
0555名無しさん@お腹いっぱい。
2010/08/09(月) 17:42:500556名無しさん@お腹いっぱい。
2010/08/09(月) 17:43:43自分で答え書いてるじゃん。
break とか continue とか実行すればいいだけ。
0557名無しさん@お腹いっぱい。
2010/08/09(月) 18:17:380558名無しさん@お腹いっぱい。
2010/08/10(火) 17:09:38mountの実行を5秒程度スクリプトのなかで遅らせたいんですが
どのようにすればよいですか?
0559名無しさん@お腹いっぱい。
2010/08/10(火) 17:43:510560558
2010/08/10(火) 22:45:52どうもです
0561名無しさん@お腹いっぱい。
2010/08/10(火) 23:18:19起動スクリプトいじるような人がまじでsleep知らなかったの?
0562名無しさん@お腹いっぱい。
2010/08/10(火) 23:29:090563名無しさん@お腹いっぱい。
2010/08/11(水) 07:33:150564名無しさん@お腹いっぱい。
2010/08/12(木) 07:22:26起動スクリプトにsleepが入ってるのは良い設計ではない。
0565名無しさん@お腹いっぱい。
2010/08/12(木) 07:34:16まあ、RHELでもこんなもんだ:
$ grep sleep /etc/init.d/* | wc -l
37
0566名無しさん@お腹いっぱい。
2010/08/12(木) 07:34:44そりゃ、RHELだもん。
0567名無しさん@お腹いっぱい。
2010/08/12(木) 07:42:15だれがgrepしてみて。
0568名無しさん@お腹いっぱい。
2010/08/12(木) 07:45:06それ、whileループ中で、あるコマンドを実行し、失敗した時のみ
sleepしてからリトライするという記述がメインなので、
通常時はsleepは実行されないし、問題ない書き方なんだよ。
0569名無しさん@お腹いっぱい。
2010/08/12(木) 12:45:45そう思うだろ?
実際見てみると、正常ルートなのに笑えるほど寝てるぜ。
0570名無しさん@お腹いっぱい。
2010/08/12(木) 12:49:580571名無しさん@お腹いっぱい。
2010/08/12(木) 13:19:05確認したけど、1番目の起動スクリプトが実行開始されてから
最後の起動スクリプトが終了するまでトータルで1秒未満なので、
sleepは1度も実行されてない。
OS起動時は、起動スクリプトの速度はネックになってなくて、
むしろ、カーネル自身のデバイス認識部分とかに時間がかかってる。
0572名無しさん@お腹いっぱい。
2010/08/12(木) 16:30:34[OK]
[OK]
・
・
・
・
が1秒以内に終わる・・・?超進化してるな。
0573名無しさん@お腹いっぱい。
2010/08/12(木) 16:52:40未だに起動が激遅なSolarisを何とかしてください。
0574名無しさん@お腹いっぱい。
2010/08/12(木) 18:59:43なぜだめなの?
0575名無しさん@お腹いっぱい。
2010/08/12(木) 19:15:53非同期処理の終了をタイミングで取る→機種依存
0576名無しさん@お腹いっぱい。
2010/08/12(木) 19:27:44単純にsleepで待ってるんじゃなくて、実際にはこういう処理だよ
↓
while ! command
do
sleep 1
done
どこにも機種依存要素はないし、
この処理で sleep を外したらそれこそ busy loop で重くなる。
0577名無しさん@お腹いっぱい。
2010/08/12(木) 19:34:39>どこにも機種依存要素はないし
こいつアホ(AAry
0578名無しさん@お腹いっぱい。
2010/08/12(木) 19:52:37いや、これ最高にアホだろ。
0579名無しさん@お腹いっぱい。
2010/08/12(木) 20:14:530580名無しさん@お腹いっぱい。
2010/08/12(木) 20:26:06ここで言う機種依存といのはハードウェア構成依存という事だろう。
0581名無しさん@お腹いっぱい。
2010/08/12(木) 20:50:29それは分かってるんだが。
大量に同一用途のサーバー管理するんでもなきゃ、
わざわざ可搬性を考慮するのなんて、バカバカしいよ。
0582名無しさん@お腹いっぱい。
2010/08/12(木) 21:19:44ぜんぜんわかってねぇなw
0583名無しさん@お腹いっぱい。
2010/08/12(木) 23:02:33反論も出来ないならひっこんでろよ
0584名無しさん@お腹いっぱい。
2010/08/12(木) 23:16:36何イライラしてるんだよw
sleep同期君
0585名無しさん@お腹いっぱい。
2010/08/13(金) 11:23:11別に問題ないと思うけど。
0586名無しさん@お腹いっぱい。
2010/08/13(金) 12:03:28そもそも非同期処理じゃないし…
0587名無しさん@お腹いっぱい。
2010/08/13(金) 12:46:070588名無しさん@お腹いっぱい。
2010/08/13(金) 13:07:37あれはタイマ割り込み使って音源鳴らしてるだけだろ。
0589名無しさん@お腹いっぱい。
2010/08/13(金) 13:08:450590名無しさん@お腹いっぱい。
2010/08/13(金) 13:43:34SMF再生するシェルが書けそうだな。
0591名無しさん@お腹いっぱい。
2010/08/13(金) 14:17:120592名無しさん@お腹いっぱい。
2010/08/20(金) 19:16:35単純に
tar directry/faile.tar tergetdir/
としてみたんですが
0593名無しさん@お腹いっぱい。
2010/08/20(金) 19:33:45シェルと関係ない話は別スレでやれよ(Makefileとも関係ないし)
まあ、f と -C オプションが落ちてるのが原因だけどな。
0594名無しさん@お腹いっぱい。
2010/08/20(金) 20:07:240595名無しさん@お腹いっぱい。
2010/08/20(金) 20:09:52faile
terget
英語初心者スレが適当だね
0596名無しさん@お腹いっぱい。
2010/08/20(金) 20:37:55オプションがないね
man tarオススメ
tar cf foo.tar bar
tar cfz foo.tar.gz bar
tar cfj foo.tar.bz2 bar
0597名無しさん@お腹いっぱい。
2010/08/20(金) 21:11:100598592
2010/08/20(金) 21:29:35tar xvfp directry/file.tar tergetdir/
でした
0599名無しさん@お腹いっぱい。
2010/08/20(金) 21:36:30■ このスレッドは過去ログ倉庫に格納されています