トップページunix
1001コメント351KB

シェルスクリプト総合 その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
0769名無しさん@お腹いっぱい。2010/09/18(土) 00:43:05
>>768
dash on Debian だと
40 70 10 0
てなったよ。

set -x
してみたらどう?
0770名無しさん@お腹いっぱい。2010/09/18(土) 00:58:52
>>768
改行コードが CR+LF になってるだろ。LFのみにしろ。

var1=100^M とかになって実行されるから、正しく数値として実行されない。
0771名無しさん@お腹いっぱい。2010/09/18(土) 01:17:44
>>769
御回答、ありがとうございます。
set -x var1=100
set -x var2=0
としましたところ、今度は下記の結果が出力されました。

$ sh test02.sh
+ set -x $'var2=0\r'
++ expr 10 + 30
+ num1=$'40\r'
++ expr - 30
expr: syntax error
+ num2=$'\r'
++ expr 100 % 30
+ num3=$'10\r'
++ expr
expr: missing operand
Try `expr --help' for more information.
+ num4=$'\r'
+ echo $'40\r' $'\r' $'10\r' $'\r\r'
10

>>769
御回答、ありがとうございます。
Meadowにて改行コードをLFのみにしようとしたのですが、メニューが英語で、
どこを触ればいいのか分かりませんでした…
メニューを日本語化できないかと検索してみたのですが、403エラーでサイトに
入ることが出来ませんでした。

質問ばかりで恐縮ですが、LFのみにする為、どこを触ればよいか教えていただけないでしょうか?
0772名無しさん@お腹いっぱい。2010/09/18(土) 01:28:30
だめだこりゃw

改行コードの問題ということがはっきりして、
このスレ的には問題解決したので、
次の方どうぞ
0773名無しさん@お腹いっぱい。2010/09/18(土) 01:33:31
>>771
$ tr -d '\r' < in > out

あと、 set の使い方が違うよ。man 見てね。
0774名無しさん@お腹いっぱい。2010/09/18(土) 01:37:53
メニューとか言ってる奴がMeadowなんて使うなよ。
C-x RET f
で, sjis-unix とか指定すればいい。
分からなかったら禿丸とかでも改行コード変更できるだろ。
0775名無しさん@お腹いっぱい。2010/09/18(土) 01:52:09
cygwin なら dos2unix
0776名無しさん@お腹いっぱい。2010/09/18(土) 08:28:48
>>768
Don't say "shell", idiot !

あ、こっちは日本語スレだった、、
0777名無しさん@お腹いっぱい。2010/09/21(火) 17:22:43
質問です。
起動したアプリケーションの終了を待たずに、次のステップを実行するにはどう書けばいいのですか?
0778名無しさん@お腹いっぱい。2010/09/21(火) 17:34:57
&
0779名無しさん@お腹いっぱい。2010/09/21(火) 17:50:04
ありがとう。
0780名無しさん@お腹いっぱい。2010/09/25(土) 08:13:01
質問です
・ findで見付かったファイルに対してそれぞれ複数のコマンドが必要な処理を行いたい
・ ディレクトリ名にスペースが含まれる可能性がある
・ 複数コマンドと言っても mv $f $f.org;sed -e '....' <$f.org >$f;rm $f.org みたいなワンライナーな処理で
汎用的に使いまわすようなものでも無い。

以上の条件をふまえると、思い付くやり方は
1. 複数のコマンド部分をシェルスクリプトにして、find -exec
2. 複数のコマンド部分をシェルスクリプトにして、find -print0 |xargs -0
3. 一時的にIFS='\n'にして、for f in `find ...`;do ....
という3つが思い付くんですが、1,2はわざわざスクリプトにするのは億劫で、3はちょっとトリッキーな感じで
どれもしっくり来ません。
割と良くある処理だと思うんですが、標準的なやり方って他に何かありませんかね?
0781名無しさん@お腹いっぱい。2010/09/25(土) 09:14:00
-exec sh -c 'mv "{}" "{}.org";sed -e ... < "{}.org" > "{}";rm "{}.org"'
0782名無しさん@お腹いっぱい。2010/09/25(土) 10:01:27
二つのファイルがあります。
一列目に日付が二列目に数字が入っているのですが
fileAにない日付のデータがfileBにはあります。
fileAになければfileBのデータを補完して新たなfileを作成したいのですが、
簡単な方法ありますでしょうか?

file A
199901 10
199902 15
199903 16
199004 17

file B
199901 18
199902 13
199903 13
199004 13
199005 18

file NEW
199901 10
199902 15
199903 16
199004 17
199005 18

というようにしたいのですがどうすればよいでしょうか。
0783名無しさん@お腹いっぱい。2010/09/25(土) 10:31:02
出力順違うけど、ダメ?

$ sort -u -k 1,1 filea fileb
199004 17
199005 18
199901 10
199902 15
199903 16
0784名無しさん@お腹いっぱい。2010/09/25(土) 12:01:48
>>781
それはちょっと面倒だなぁ。
0785名無しさん@お腹いっぱい。2010/09/25(土) 12:07:30
応用力の無い奴だな。
-exec sh -c 'f="{}"; mv "$f" "$f.org";sed -e ... < "$f.org" > "$f";rm "$f.org"'
0786名無しさん@お腹いっぱい。2010/09/25(土) 13:17:19
>>785
それはもっと面倒だなぁ。
0787名無しさん@お腹いっぱい。2010/09/25(土) 13:42:32
>>785
タイプ数増やして応用力とはこれ如何にw

findで見つかったファイル名の中に $ を含むもの( $hoge という名前のファイルとか)
があったら、f="{}" のところで展開されちゃうから、エンバグしてるじゃん。
0788名無しさん@お腹いっぱい。2010/09/25(土) 14:11:13
>>787
そのバグは >>781 に既に含まれてるから、「エンバグ」ではない。
あと、$だけじゃなくて " ` とかがあってもコケるな。
0789名無しさん@お腹いっぱい。2010/09/25(土) 14:27:21
>>783
ありがとうございます!
試してみます!
0790名無しさん@お腹いっぱい。2010/09/26(日) 19:42:22
>>789

出力順を変えない方法もあるよ:

$ cat file_A file_B | awk '!a[$1]++'
0791名無しさん@お腹いっぱい。2010/09/26(日) 20:09:55
フォルダ内のdebパッケージを連続で
dpkg -x xxx.deb xxx
するスクリプトを作りたいんですが、
xxx.deb から .debを削除するには?
0792名無しさん@お腹いっぱい。2010/09/26(日) 21:08:35
basename xxx.deb .deb
07937912010/09/26(日) 22:09:55
>792
sedを使うのかと思ってました。
basenameってこう言う使い方ができたんですね。
ありがとうございました。
0794名無しさん@お腹いっぱい。2010/09/27(月) 00:00:54
>>793
普通は、
for f in *.deb;do dpkg -x $f ${f%.deb};done
だけどな。
07957932010/09/27(月) 06:55:47
>794
おー スマートですね
0796名無しさん@お腹いっぱい2010/09/29(水) 18:50:18
あるプロセスの稼働をチェックするため
PROC=`ps ax | grep "process"`
if [ -n "$PROC" ]
then
として見たら、grep processがあるからダメなのね
どうすりゃいいの?
0797名無しさん@お腹いっぱい。2010/09/29(水) 18:54:03
>>796
pgrepないの?
0798名無しさん@お腹いっぱい。2010/09/29(水) 18:55:07
grep -v grepはできない?
0799名無しさん@お腹いっぱい。2010/09/29(水) 18:56:12
>>798
見たいプロセスが logreport.sh とかだった場合に困る。
0800名無しさん@お腹いっぱい。2010/09/29(水) 19:00:16
grep '[p]rocess' みたいなテクよくみかけたけど
0801名無しさん@お腹いっぱい。2010/09/29(水) 19:03:33
そういう小技こねくりまわすよりpgrep使う方が楽だと思うけどな。
ない環境ならしょうがないけど。
0802名無しさん@お腹いっぱい。2010/09/29(水) 20:45:17
>>801
そりゃ、PerlやRuby、Pythonなどが普及しても
「どこでも通じるからawkは覚えておいたほうがいい」なんてのがUNIX文化。

そこにおいて >801 は異質に見える。
0803名無しさん@お腹いっぱい。2010/09/29(水) 20:48:45
awkがどこでも使えるとは初めて知った
0804名無しさん@お腹いっぱい。2010/09/29(水) 20:52:30
>>803

必死だな。
0805名無しさん@お腹いっぱい。2010/09/29(水) 20:53:03
awkが使えないOSがあるなんていう奴初めて見た
0806名無しさん@お腹いっぱい。2010/09/29(水) 21:10:00
理論馬鹿が振りかざす「どこでも」はいったいどこまで広がるんだろう。
0807名無しさん@お腹いっぱい2010/09/29(水) 21:15:56
ごめん、言いだしっぺだけど
pgrepは使えませんでした

で、板が代わって、そういう小技こねくりまわした方法が見れない

もう一度、書いてもらえる雰囲気じゃない?
0808名無しさん@お腹いっぱい。2010/09/29(水) 21:23:48
awk使えばいいよ
0809名無しさん@お腹いっぱい。2010/09/29(水) 21:23:54
組み込み系のbusyboxでもawkは欠かせないからな。
いまいじっているシステムは全部で16Mぐらいの/
だけど、awkはある。pgrepはない。
perlもpythonもbashもない。

こういうシステム上でもinitスクリプト等にawkは必須。
0810名無しさん@お腹いっぱい。2010/09/29(水) 21:24:54
>>809
必死な屁理屈野郎にはなに言っても無駄だと思うよ。
0811名無しさん@お腹いっぱい。2010/09/29(水) 21:59:51
そういうのは最低限LLでやるべきだろ。
実際Perlとかで書いてみて、
シェルスクリプトと比べてみるといいよ。
0812名無しさん@お腹いっぱい。2010/09/29(水) 22:03:17
>>807
>>800が定石だと思う.
08138072010/09/29(水) 22:15:12
>812
ありがとう
0814名無しさん@お腹いっぱい。2010/09/30(木) 00:48:34
nawkかgawkか確認すべき
0815名無しさん@お腹いっぱい。2010/09/30(木) 10:48:54
ガウォーク
0816名無しさん@お腹いっぱい。2010/09/30(木) 18:11:46
条件がそろった時にメールを送る
このスクリプトをcrondで1時間ごとに起動する
1度メールすると次は送らない
とするなると、メールを送ったかどうかの、何らかのフラグが必要でけど
一般的には、何をフラグとすればいいでしょうか?
ファイルの有無?
ファイルの中身の有無としたとき、ファイルのテキストを空にするコマンド
ってありました。?
0817名無しさん@お腹いっぱい。2010/09/30(木) 18:16:59
>
0818名無しさん@お腹いっぱい。2010/09/30(木) 18:18:11
>>816
> 1度メールすると次は送らない

生涯で1回しかメール送らないってこと?

> ファイルの中身の有無としたとき、ファイルのテキストを空にするコマンド
> ってありました。?

:>file みたいな
0819名無しさん@お腹いっぱい。2010/09/30(木) 18:37:44
>>817 の勝ち

>>818
コロンが無駄です
0820名無しさん@お腹いっぱい。2010/09/30(木) 18:53:06
あ、そう言うことですか
サンキュー
0821名無しさん@お腹いっぱい。2010/09/30(木) 19:13:37
> は zsh とか csh とかでは違う動作になるので
どこでも動く :> の方が安心といえば安心。
まあ、sh と zsh をごっちゃにする人はあんまりいないと思うけど。
0822名無しさん@お腹いっぱい。2010/09/30(木) 22:01:22
cat /dev/null > file などとやってた俺はダサイな。

':' って初めて知ったが他にどんな使い方があるのなか?
0823名無しさん@お腹いっぱい。2010/09/30(木) 22:03:02
while :
0824名無しさん@お腹いっぱい。2010/09/30(木) 22:05:11
while : で無限ループとか
: ${FOO:=bar} で変数のデフォルト値設定とかか?
0825名無しさん@お腹いっぱい。2010/09/30(木) 22:44:52
cp /dev/null file派
は俺だけか?
0826名無しさん@お腹いっぱい。2010/09/30(木) 22:46:07
そんなダサいことしてるのは流石にお前だけだろ…
0827名無しさん@お腹いっぱい。2010/09/30(木) 22:53:06
>>822
そっちの方が、誰が見てもわかりやすいってのはあるがな。
0828名無しさん@お腹いっぱい。2010/09/30(木) 23:10:03
条件の否定形が見易い形に書けなくて

if 肯定の条件;
:
else
本来やりたいこと
fi

みたいなの書いたことがある。

0829名無しさん@お腹いっぱい。2010/10/01(金) 00:38:18
長い行を折り返すために、キリがいいからって、>file の前で折り返したスクリプトを見たことがあるw
0830名無しさん@お腹いっぱい。2010/10/01(金) 01:02:16
>>828
if ! ( 肯定の条件 );
本来やりたいこと
fi

じゃだめ?
0831名無しさん@お腹いっぱい。2010/10/01(金) 06:13:44
>>830
純正シェルで動かない
0832名無しさん@お腹いっぱい。2010/10/01(金) 10:44:57
:<<'_'
複数行のコメント
_
0833名無しさん@お腹いっぱい。2010/10/01(金) 10:54:38
>>832
それもコロンが無駄です
0834名無しさん@お腹いっぱい。2010/10/01(金) 13:34:00
内部的にTMPファイルまたはパイプを作る動作は起きるから、
完全なコメントアウトになってないのが問題だな。
0835名無しさん@お腹いっぱい。2010/10/02(土) 18:57:00
皆様のお知恵を拝借したく
Linux bash3.2.25 の環境です

関数がいくつかあって、ある関数内(Aとします)の条件式(if)で分岐した結果、異なる関数(Bとします)を
呼び出したとします。
その呼び出された関数Bの処理が終わった後、直前に実行してた関数Aに戻る方法はないでしょうか?

何をしたいかというと、Aで実行したコマンドの結果の判定を行い正だった場合に
関数Bに移動してそこでwhileを使ってカウンタを増やし、また関数Aに戻ってコマンドを実行し
偽になるまで繰り返したいのです。(偽になったら関数A内のif文で抜けて次の関数Cへと進みます)

どなたか良い方法を教えていただけると助かります
0836名無しさん@お腹いっぱい。2010/10/02(土) 19:02:53
>>835
関数というのは、処理が終れば呼び出し元に戻る。
だから何もしなくても関数Aに戻るよ。
逆に、関数A「以外」に戻ることはできない。
0837名無しさん@お腹いっぱい。2010/10/02(土) 19:08:25
>>836
わぁ、すみません・・・
仰る通りでした。途中で別の所を呼んでたのをすっかり忘れておりました。
お手数おかけしました・・・
0838名無しさん@お腹いっぱい。2010/10/04(月) 15:12:52
次はLinux板で聞いてね。
0839名無しさん@お腹いっぱい。2010/10/04(月) 16:19:30
>>838
別にLinux依存の質問じゃないし、こっちで聞いていいよ。
あと、Linux板のシェルスクリプトスレは落ちて終了したから、こっちで聞くしかない。
0840名無しさん@お腹いっぱい。2010/10/04(月) 16:43:16
くだ質で聞けばいいんじゃね。
0841名無しさん@お腹いっぱい。2010/10/06(水) 11:17:31
出力をしたくないときによく
./hogehoge >/dev/null 2>&1
とやりますが、なぜリダイレクトは後ろから評価されるのですか?
この順序に例外はありますか?
0842名無しさん@お腹いっぱい。2010/10/06(水) 11:36:15
>>841
後ろから評価されてないよ。

2>&1 は 標準エラーを標準出力と同じところに出力するということ。
./hogehoge >/dev/null 2>&1
の場合は 2>&1 が評価された時点で、標準出力が /dev/null に設定されている
ので、標準エラーも /dev/null に設定される。

./hogehoge 2>&1 >/dev/null
この場合は 2>&1 が評価された時点で、標準出力が画面に表示される設定になっ
ているから、標準エラーが画面表示される。

分かり難い説明だと思うので、検索したほうがいいかも。
0843名無しさん@お腹いっぱい。2010/10/06(水) 11:38:50
後ろからじゃ無くて前からだよ。
1 >/dev/null 標準出力を/dev/nullにリダイレクトする。
2 2>&1 標準エラーを(さっき/dev/nullにリダイレクトした)標準出力にdupする。

感覚に合わないのは、./hogehoge 2>&1 | hagedebu
これは、標準出力をパイプにリダイレクトするのが先。
0844名無しさん@お腹いっぱい。2010/10/06(水) 11:43:35
まぁ dup2 について調べろってことだな
0845名無しさん@お腹いっぱい。2010/10/06(水) 11:46:57
もうちょっとお母さんみたくやさしく
0846名無しさん@お腹いっぱい。2010/10/06(水) 12:06:42
「リダイレクトは後ろから評価される」と、
間違いを堂々と書いてるサイトや文章が結構存在するから注意。

正しくは「前から評価される」
「ファイル記述子の複製」を理解すれば理解できる。
0847名無しさん@お腹いっぱい。2010/10/06(水) 12:19:14
うちの社員研修では「リダイレクトは後ろから評価される」と教えてます。
正しいかどうかよりもわかりやすさ優先なので。
何か問題でも?
0848名無しさん@お腹いっぱい。2010/10/06(水) 13:13:08
>>846
ここでわからないとされるのは、前から評価されるなら
2>&1 で標準エラー出力(2)を標準出力(1)にしたときに
そのあと >/dev/null にしたときに なぜ元標準エラー出力は
釣られないのか というところだろ。
ここを簡潔に説明するのに必要なのはdupの勉強ではない
0849名無しさん@お腹いっぱい。2010/10/06(水) 14:02:53
>>846,847
なんで、マニュアルに書いてあることを無視するん?
0850名無しさん@お腹いっぱい。2010/10/06(水) 20:27:44
テンプレにある、これが元凶だなw

>/bin/shプログラミング入門
>ttp://freebooks.info.nara-k.ac.jp/archive/ShellProgramming/?

つぎのスレから、削除するべき。
0851名無しさん@お腹いっぱい。2010/10/06(水) 20:33:17
>>841>>847
後ろから評価されるって思うには、どういう風に解釈すればいいの?

普通、2>&1 を「stderrにstdoutと同じにする」って読むと思うけど
これだと、前から後ろに順番に読まないと意味が合わないよね

読み方が違う?もっと根本的なところが違う?
0852名無しさん@お腹いっぱい。2010/10/06(水) 20:34:18
>>普通、2>&1 を「stderrをstdoutと同じにする」って読むと思うけど 
の間違い・・・
0853名無しさん@お腹いっぱい。2010/10/06(水) 20:54:30
foo 1>file 2>file
として、書き出される順番が揃わなくて考えこんだ日を思い出した
0854名無しさん@お腹いっぱい。2010/10/06(水) 23:17:59
>>852
言い直したところでその説明だと致命的におかしいのぜ。

ls -e 2>&1 >hoge.txt
のとき、標準エラー出力はhoge.txtに吐かれない。
「stderrにstdoutと同じにする」 と読んでしまったら
評価順序的にhoge.txtに吐かれないとおかしいだろ。
同じになったんだから。

「同じにする」という理解方法が間違い・
0855名無しさん@お腹いっぱい。2010/10/07(木) 00:11:24
1とか2は、「ファイルディスクリプタ」
 (ハンドルみたいなものかな?)

に対して、stdoutとかstderrは、「ファイル」そのもの。

これらを混同するから、わからなくなるだけ。



>>853
さらに、バファリンが絡んできて、わけわかめ?
0856名無しさん@お腹いっぱい。2010/10/07(木) 06:40:07
>>855
>stdoutとかstderrは、「ファイル」そのもの。

↑違うよ。

stdoutとかstderrはそれぞれファイル記述子1と2の別名。
例えば、hoge 2>&1 と、 hoge 2> /dev/stdout は同じ動作。

ファイルそのものはまた別。
0857名無しさん@お腹いっぱい。2010/10/07(木) 12:22:41
>>855
「FILEそのもの」と書きたかったのかな。

FILEは「ファイル」じゃなく「ファイルハンドル」
ファイルでスクリプタも、UNIX固有の特殊なファイルハンドル for システムコール。
0858名無しさん@お腹いっぱい。2010/10/07(木) 14:08:17
そういえば、標準エラー出力と標準出力を入れ替える手段って無くね?
0859名無しさん@お腹いっぱい。2010/10/07(木) 14:25:35
>>858
hoge 3>&2 2>&1 1>&3

じゃ駄目?
0860名無しさん@お腹いっぱい。2010/10/07(木) 14:36:36
>>859
うまくいった・・・

となると今までの評価順序の話は根底から崩れる予感。
&3 って誰だよって話
0861名無しさん@お腹いっぱい。2010/10/07(木) 14:38:14
もう面倒くさいから「後ろから評価される ように 動作する」でいいよ。
0862名無しさん@お腹いっぱい。2010/10/07(木) 14:47:10
>>861
「後ろから評価される ように 動作する」と考えると、
>>859 で stderrとstdoutを入れ換える動作が説明できない。
0863名無しさん@お腹いっぱい。2010/10/07(木) 14:50:32
>>860
> となると今までの評価順序の話は根底から崩れる予感。
> &3 って誰だよって話

最初から全然理解できてないだけじゃん。
0864名無しさん@お腹いっぱい。2010/10/07(木) 16:46:04
>>863
説明よろしくお願いします
0865名無しさん@お腹いっぱい。2010/10/07(木) 17:38:30
3>&2 : dup2(2,3) 3を2と同じところにつなぐ
2>&1 : dup2(1,2) 2を1と同じところにつなぐ(3は元の2の先(stderr)のまま)
1>&3 : dup2(3,1) 1を3と同じところにつなぐ(2は元の1の先(stdout)のまま)
0866名無しさん@お腹いっぱい。2010/10/07(木) 21:44:59
そんなことより、どう考えれば後ろから評価されるように
見えるのか教えてくれ
0867名無しさん@お腹いっぱい。2010/10/07(木) 23:06:21
>>866
自分で考えろよ
0868名無しさん@お腹いっぱい。2010/10/07(木) 23:13:57
(man 2 open , man 2 dup2 じゃ) いかんのか
■ このスレッドは過去ログ倉庫に格納されています