トップページ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
0727名無しさん@お腹いっぱい。2010/09/14(火) 23:12:17
>>726
>>723 は date自体を使わずに、日付の数値を自分で計算しろと言ってるのでは?
0728名無しさん@お腹いっぱい。2010/09/14(火) 23:54:36
閏年とか面倒ならその辺はcalに任せればいいのでは。
0729名無しさん@お腹いっぱい。2010/09/15(水) 00:04:20
参考: 指定月の月末日を求める

set `cal 8 2010`; shift `expr $# - 1`; echo $1
0730名無しさん@お腹いっぱい。2010/09/15(水) 01:02:19
>>729
おもしろいやり方してるな。
俺は普通にgrepとtailとsedあたりでやることを考えてしまうんで、ちょっと新鮮だ。
0731名無しさん@お腹いっぱい。2010/09/15(水) 01:07:27
可搬性はあまり確かめてないけど、Mac(BSD系)では動いてる気がする。

cal 8 2010 | tr -s ' ' '¥012' | sed -n '$p'
0732名無しさん@お腹いっぱい。2010/09/15(水) 01:23:18
>>731
Solaris 10, Ubuntu 10.04はokだった。
0733名無しさん@お腹いっぱい。2010/09/15(水) 02:32:21
>>729
arg配列のそんな使い方があったのか。 自分が思いつくのは普通の
配列だな。

$ DAYS=(`cal 8 2010`); echo ${DAYS[`expr ${#DAYS[*]} - 1`]}
0734名無しさん@お腹いっぱい。2010/09/15(水) 16:35:01
grepとかsedみたいにshで出力を処理したいんだけど

./example | while read x
do
 なんか処理して変数代入とか
done
変数を利用して後処理

というのをパイプ(サブシェル)を使わずにできない?
変数相当の値を一旦外部ファイルに書き出さないと駄目かな

exampleの出力を自身の入力にできるといいんだけど

0735名無しさん@お腹いっぱい。2010/09/15(水) 16:51:27
>>734

RESULT=`./example | while read x
do
 なんか処理して echo 処理結果
done`

"$RESULT" を利用して後処理
0736名無しさん@お腹いっぱい。2010/09/15(水) 17:44:06
./example |{ while read x; do ... done; echo $hoge;}
のようにすれば、while の外に出ても {} の内側にいるかぎりは変数の値が見える。

以下のようにすればそもそもサブシェルが生成されないが、
何やってるのかひじょーにわかりにくいのでオススメはしない。
while read x; do ... done <<_EOF_
`./example`
_EOF_

bash 限定。
while read x; do ... done <<<"`./example`"
0737名無しさん@お腹いっぱい。2010/09/15(水) 19:46:27
#!/bin/sh

[ -z "$HOGE" ] && { ./example | HOGE=hage exec $0; }

while read x; do
 なんか処理して echo 処理結果
done
07387162010/09/16(木) 01:30:00
cal…正にこれが求めていたものです!
UNIXを初めて触ったころには使っていましたが、
それ以来一切関わることなく脳内から完全に抜け落ちていました。
cal出力の最後を月末とすることでうまくいきそうです。
レスくれた方ありがとうございました!
0739名無しさん@お腹いっぱい。2010/09/16(木) 19:10:11
cal はK&Pの「環境」のシェルスクリプトを作成する例で使用されていて、
斯界のおっさんたちは皆一度は試してるんだぞぉ
07407342010/09/16(木) 19:11:08
>>735>>736>>737
thx!

737は思いもつかなかったが、こういう書き方もあるのか

0741名無しさん@お腹いっぱい。2010/09/16(木) 19:23:19
>>737 って環境によってはハングして動かないよ。
ネタで書いてると思ったよ。
0742名無しさん@お腹いっぱい。2010/09/17(金) 07:42:06
どんなヘボシェルだよ。ww
0743名無しさん@お腹いっぱい。2010/09/17(金) 08:09:55
>>742
FreeBSDの/bin/shで、>>737 動かないよ。

たしかにFreeBSDはヘボだな。
0744名無しさん@お腹いっぱい。2010/09/17(金) 08:31:55
これならヘボいのでも動くだろう。
[ -z "$HOGE" ] && { ./example | HOGE=hage $0; exit; }
0745名無しさん@お腹いっぱい。2010/09/17(金) 08:41:25
逆に、>>737 が動くようなシェルなら、
わざわざこんなことしなくても、
command | while ... がサブシェルにならないから、

最初から command | while ... と書けばいいんだな。

よって、>>737 は全然解決になってない。
0746名無しさん@お腹いっぱい。2010/09/17(金) 08:51:57
改訂版が出てるんだから、言いがかりならそっちに付けろよ。w
0747名無しさん@お腹いっぱい。2010/09/17(金) 09:09:00
採点が終ってから答を直しても単位はあげられないんだよ
0748名無しさん@お腹いっぱい。2010/09/17(金) 09:15:55
同じサブシェル問題だと、後付けで気付いて言いがかり付けでもダメ。ww
0749名無しさん@お腹いっぱい。2010/09/17(金) 09:18:43
>>748
同じサブシェル問題だと、後付けで気付いたのはお前の方だろw
俺は最初からわかってたよ。
0750名無しさん@お腹いっぱい。2010/09/17(金) 09:22:05
> 俺は最初からわかってたよ。
> 俺は最初からわかってたよ。
> 俺は最初からわかってたよ。
> 俺は最初からわかってたよ。
> 俺は最初からわかってたよ。
0751名無しさん@お腹いっぱい。2010/09/17(金) 09:36:12
少なくとも
>>742 >どんなヘボシェルだよ。ww

↑って書いてる時点で 742 はサブシェル問題だと気付いてないよね。

FreeBSDだけじゃなく、フツーのbourne shでは動かないことに
この時点でまだ気づいてないww
0752名無しさん@お腹いっぱい。2010/09/17(金) 09:38:58
わかっていなくても、試すだけで>>741は書けるからな。
> 俺は最初からわかってたよ。
と言いたいのだったら最初から書くべきだったな。ww
0753名無しさん@お腹いっぱい。2010/09/17(金) 09:43:14
>>752
最初からわかってたのは本当だ。
でも答を書いてしまうと面白くないから >>737 他の反応を見るために書かなかった。
「ネタで書いてると思ったよ」という言葉に、
「サブシェル問題の解決なのにサブシェル問題に引っかかってるという笑いネタかw」
というニュアンスを含ませたつもりだが、読みとれなかったかい?
0754名無しさん@お腹いっぱい。2010/09/17(金) 09:45:10
涙ぐましい渾身の後付け言い訳。ww
0755名無しさん@お腹いっぱい。2010/09/17(金) 09:48:05
はっきり言えることは、
>>737 自身が 737 を書いた時点で、
「全然問題の解決になってない」ということを理解していなかったということだ。

これだけは紛れもない事実。
0756名無しさん@お腹いっぱい。2010/09/17(金) 09:52:19
事実は
> 俺は最初からわかってたよ。
と、>>741が後付けで必死に言い張っている事。
0757名無しさん@お腹いっぱい。2010/09/17(金) 09:54:04
>>756
741 をいくら叩いても >>737 の恥ずかしさを弁解できないことは理解してますか?
0758名無しさん@お腹いっぱい。2010/09/17(金) 09:56:58
>>742
0759名無しさん@お腹いっぱい。2010/09/17(金) 10:10:47
>>757
バグはそんなに恥ずかしくない。後付けで↓と言い張るよりは。
> 俺は最初からわかってたよ。
> 俺は最初からわかってたよ。
> 俺は最初からわかってたよ。
> 俺は最初からわかってたよ。
0760名無しさん@お腹いっぱい。2010/09/17(金) 10:20:59
>>759
じゃあ、バグを認めずに(バグの原因を理解せずに)
>>742 「どんなヘボシェルだよ。ww」

って言うのはどれくらい恥ずかしいですか?
0761名無しさん@お腹いっぱい。2010/09/17(金) 10:39:20
子供かよ。
0762名無しさん@お腹いっぱい。2010/09/17(金) 10:42:05
それより、>>737 自身は動作確認したんだろうか?

それとも、/bin/sh -> zsh みたいにリンクされたOS使ってたのか?
0763名無しさん@お腹いっぱい。2010/09/17(金) 11:51:22
そういう質問が出ることも最初から分かっていました
0764名無しさん@お腹いっぱい。2010/09/17(金) 11:59:58
>>763
で、762の質問への回答は?
(1)動作確認してなかったのか、(2)/bin/sh -> zsh にしてたのか?(その場合はOS名も)
0765名無しさん@お腹いっぱい。2010/09/17(金) 17:52:57
>>760 ↓これの100分の1くらいかな。w
> 俺は最初からわかってたよ。

>>762
確認してないが何か?
0766名無しさん@お腹いっぱい。2010/09/17(金) 17:57:23
>>765
>確認してないが何か?
>確認してないが何か?
>確認してないが何か?
>確認してないが何か?

あーあ。自爆、敗北宣言乙w
0767名無しさん@お腹いっぱい。2010/09/17(金) 18:01:20
確認してない事と、お前が後付けで知ったかぶりした事は全く独立なんだが。
どこが敗北宣言なんだろう。ww
0768名無しさん@お腹いっぱい。2010/09/18(土) 00:37:33
すみません、質問させて下さい。
シェルスクリプトの練習の為、練習用のシェルスクリプトを作成しており、
Cygwin上にて

#!/bin/sh
var1=100
var2=0
num1=`expr 10 + 30`
num2=`expr $var1 - 30`
num3=`expr 100 % 30`
num4=`expr $var2 && 1000`
echo $num1 $num2 $num3 $num4

という、上記内容のシェルを実行しました。
下記のような結果が出力される予定でした。

$./script2
40 70 10 0

ところが、

expr: non-integer argument
test02.sh: line 7: 1000: command not found
00

という内容が出力されてしまいました。
$var1、$var2が認識されていないようなのですが、原因が分かりません。
シェルはbash、OSはWindowsXPSP3です。
何卒、御教授お願い致します。
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
そんなダサいことしてるのは流石にお前だけだろ…
■ このスレッドは過去ログ倉庫に格納されています