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

シェルスクリプト総合 その5

■ このスレッドは過去ログ倉庫に格納されています
0001名無しさん@お腹いっぱい。2006/01/21(土) 09:00:29
シェルスクリプトの総合スレです。
スクリプトのお勉強・自慢・腕試しなどにどうぞ。
まずは注意点、リンク、地鎮祭など(>>1-6くらい)をご覧ください。


□お約束
・特記なき場合はbourne shがデフォルトです。
 bash/csh/tcsh/zsh/ksh/ashなどに依存する場合は明示しましょう。
 Linuxユーザは/bin/shの正体がbashなので特に注意。
・UNIXにはシェルスクリプトに便利な小さなコマンドがいろいろあります。
 manや参考リンクを見ましょう。
 aproposないしはman -kでそれらしい単語による簡単な検索もできます。
・シェルスクリプトのことをシェルってゆーな
・シェルで使えるワイルドカード等は正規表現ではありません。
正規表現の話題はスレ違い(正規表現スレへ)

□初心者へのアドバイス:
・適した道具を判断するのも頭の重要な使い方。シェルスクリプトよりも
 RubyやPerlの方が適した仕事には素直にそちらを使いましょう。
・知らないコマンドが出てきたらmanを引きましょう。
・思い通りに動かないときは、まずは sh -x でトレースしましょう。
0781名無しさん@お腹いっぱい。2006/03/17(金) 13:51:05
はやくUNIX書けよ
0782名無しさん@お腹いっぱい。2006/03/17(金) 13:58:49
>>777
> 初心者の質問に、誰かが man嫁と回答してるのを見て、
> その直後にもっとずばりの回答をしてるのがオレ。
質問者が調べる機会を奪っちゃいかんよ。
0783名無しさん@お腹いっぱい。2006/03/17(金) 14:25:41
>>777
でもオマエmanの入れ方解らないで教えてもらったじゃん
0784名無しさん@お腹いっぱい。2006/03/17(金) 16:11:11
僕にもmanの入れ方教えてくださいm(_ _)m
0785名無しさん@お腹いっぱい。2006/03/17(金) 17:15:07
結局manが使えないバカの再教育からUNIX打たないとダメか
0786名無しさん@お腹いっぱい。2006/03/17(金) 21:56:29
>>777
どのようにして、その先入観を打ち破る事が出来るのか。本当に悩ましい
0787名無しさん@お腹いっぱい。2006/03/17(金) 22:14:27
>>786
そのネタもう古い。もっと新しいの頼む。
0788名無しさん@お腹いっぱい。2006/03/17(金) 23:57:09
ずばりの回答か・・・ま、ほんとにずばりならいいが。
0789名無しさん@お腹いっぱい。2006/03/18(土) 00:07:22
ずっぽりの回答
0790名無しさん@お腹いっぱい。2006/03/18(土) 00:18:15
相変わらずレベル低いなw
0791名無しさん@お腹いっぱい。2006/03/18(土) 12:04:50
ここはmanについて考えるスレかよ!
man入れるか入れないかは別として回答としては>>701が一番良いと思うけどな。
>>699の人はある程度調べた後に質問したように見えるし、調べる方向が間違いつつあるようにも見える。
そういう人にはそのものずばりの回答を出せば、その人は自分で man date で回答を確かめる事をすると
思うよ。
0792名無しさん@お腹いっぱい。2006/03/18(土) 12:28:56
>>791
だから?
要するに君はここが相変わらずレベル低いと言いたかったわけだね
0793名無しさん@お腹いっぱい。2006/03/18(土) 13:22:42
>>791
ジサジエも飽きたから何か変わったUNIXを振ってくれよ
07947912006/03/18(土) 13:35:17
>>793
俺は701では無い。
manも入れてる。
ねたは無い。
0795名無しさん@お腹いっぱい。2006/03/18(土) 13:39:28
十代に若返ってナオンとずっこんばっこんできるスクリプトをお願いします
0796名無しさん@お腹いっぱい。2006/03/18(土) 14:01:41
>>795

#!/bin/sh
if [ $# -lt 1 ]; then
echo 'usage: manco YourAge' 1>&2
exit 1
fi
thisyear=`date +%Y`
year=`expr $thisyear - $1 + 16`
sudo date 01010000$year
echo 'Happy old year!'

man co
0797名無しさん@お腹いっぱい。2006/03/18(土) 14:03:36
動かしていると、自然にディレクトリ中にスクリプトが増えていくのはワームですか。
0798名無しさん@お腹いっぱい。2006/03/18(土) 14:13:13
バグです
0799名無しさん@お腹いっぱい。2006/03/18(土) 14:37:08
>>796
ありがとうございます。
早速実行してみましたが、
53歳だと、dateの実行のところでエラーになって
16歳に戻れません。
53歳以上にも対応したUNIXを打つ方法はありませんか?
08007962006/03/18(土) 14:44:14
>>799
楽観的な仕様と引数の範囲チェック無しで作成してしまいました。

>>793さん、変わったUNIXが振られましたのでよろしく。
0801名無しさん@お腹いっぱい。2006/03/18(土) 14:47:10
>>794
典型的な自作自演の告白乙
ココではそんなお約束は書かなくてもおk
0802名無しさん@お腹いっぱい。2006/03/18(土) 21:09:36
よしきた、俺にまかせろ!
俺は801では無い。
manは入れてない。
いつもずっぽり。
0803名無しさん@お腹いっぱい。2006/03/18(土) 21:18:06
Sambaで coding system = hex で運用されていたサーバーがあります。
これを、coding system = euc に変更したいので、
hexでエンコードされた「:」入りの日本語ファイル名をすべて
EUCに変換したいのですが、
どういうシェルを書いて、どういうUNIXを打てばいいでしょうか?
0804名無しさん@お腹いっぱい。2006/03/18(土) 22:07:30
書かんでよい。よってスレ違い。
http://www.samba.gr.jp/project/contrib/smbchartool.html
0805名無しさん@お腹いっぱい。2006/03/18(土) 22:23:41
>804
それ、、、以前使ったら、シンボリックリンクも全部おいかけられて、
1つのファイル名を何度も何度もコード変換されて、全部の日本語
ファイルが化け化けになったw
0806名無しさん@お腹いっぱい。2006/03/18(土) 23:07:48
じゃあ、
http://ftp.yz.yamagata-u.ac.jp/pub/network/samba-jp/tool/smbjcode/
のsmbjconv.plで、
find . -type f -exec mv {} `echo {} | /tmp/ss/smbjconv.pl hex euc` \;
0807名無しさん@お腹いっぱい。2006/03/18(土) 23:14:32
>>806
findの -execのところに ` ` 書いても期待通りに動作しないと思うぞ。
0808名無しさん@お腹いっぱい。2006/03/18(土) 23:59:27
find実行される前に展開されんだろ
0809名無しさん@お腹いっぱい。2006/03/19(日) 00:18:50
>>798
うーん、795の意図を正確に処理したら、
子プロセスがたくさん出来て困るんですけど。
0810名無しさん@お腹いっぱい。2006/03/19(日) 01:37:00
すいませんが、お力を貸してください
実行されたらあるディレクトリがあるか調べて
そのディレクトリが存在していれば○○
存在していなければ停止

このようなシェルスクリプトはどう書けばいいのでしょうか?
できればbashとshの両方が知りたいです
0811名無しさん@お腹いっぱい。2006/03/19(日) 01:47:49
>>810
man test
0812名無しさん@お腹いっぱい。2006/03/19(日) 04:34:39
>>810

if [ -d あるディレクトリ ]
then
○○
else
停止
fi
0813名無しさん@お腹いっぱい。2006/03/19(日) 06:04:35
>>810

A = 'ps ax | grep あるディレクトリ | wc -l'

if [ $A ]; then
○○
else
停止
fi
0814名無しさん@お腹いっぱい。2006/03/19(日) 06:05:20
>>810街がえっタ

A = 'ls | grep あるディレクトリ | wc -l'

if [ $A ]; then
○○
else
停止
fi
0815名無しさん@お腹いっぱい。2006/03/19(日) 09:02:40
>>813-814
何がしたいんだ? >>812の正解のあとで間違った答えを出して
0816名無しさん@お腹いっぱい。2006/03/19(日) 09:26:29
で、>>806 だと不正解なわけだが、誰も正解はわからないのかな?
0817名無しさん@お腹いっぱい。2006/03/19(日) 09:26:39
>>813
君も man test
0818名無しさん@お腹いっぱい。2006/03/19(日) 09:32:34
>>811 man で回答するのヤメレ。

>>812 正解。

>>813-814 初心者かな? >>812 の正解を参照汁。
それだとディレクトリがなくても wc -l の結果の 0 が Aに入るので、
ifで常に結果が真になる。grepでの判定も曖昧。
そんなことしなくても [ -d hoge ] でできることを覚えろ。
0819名無しさん@お腹いっぱい。2006/03/19(日) 09:34:42
>>811,817
おまえら一生manだけ読んでろ。manを読むばかりで手を動かさない机上の空論者だな。
0820名無しさん@お腹いっぱい。2006/03/19(日) 09:40:23
>>808
はぁ?
>>806 はfind実行する前に ` `が展開されるよ。
しかも、find の -exec のあとは直接のコマンドであって、
シェルスクリプトではないため、
-execの実行時には一切のシェルの解釈を受け付けない。
だから、仮に ` ` がfindの実行前に展開されていないとすると、
逆に -exec の時に ` ` がエラーになる。
いずれにしても、>>806 は大間違い。

俺は正解を知ってるが、回答者バトルのために敢えて書かない。
わかるモン居たら書いてみろ。
0821名無しさん@お腹いっぱい。2006/03/19(日) 09:50:16
エレガントなずっこんばっこんスクリプトまだー?
0822名無しさん@お腹いっぱい。2006/03/19(日) 10:45:01
>>820
熱くなりすぎ。>>808>>807への突っ込みだと取ったんだが。
0823名無しさん@お腹いっぱい。2006/03/19(日) 13:05:49
>>807 の指摘は正しい。
それに突っ込んでる >>808 は間違い。
おおもとの >>806 が間違いなのは言うまでもないが。
0824名無しさん@お腹いっぱい。2006/03/20(月) 12:00:36
>>818
私英語苦手・・・・じゃなくて、日本語苦手。
0825名無しさん@お腹いっぱい。2006/03/20(月) 14:43:21
ほげ
0826名無しさん@お腹いっぱい。2006/03/20(月) 16:27:41
ぴよ
0827名無しさん@お腹いっぱい。2006/03/20(月) 16:36:01
>>824
アンカー先間違えてる?
818にそう言っても話が繋がらないのだが・・
0828名無しさん@お腹いっぱい。2006/03/20(月) 16:51:18
つながらなくて困るようなスレの流れじゃないし。
0829名無しさん@お腹いっぱい。2006/03/20(月) 21:22:48
質問です。

カレントディレクトリ以下(サブディレクトリ含)にある.c,.cc,.cppのファイル数を知りたいのですが、どうしたらよいのでしょうか。
find ./* -name *.c | wc -l
をそれぞれの拡張子で、では無く、一発で3種類のファイル数を求める方法を知りたいです。

後、
./script < inputfile
と入力した時、inputfileの中身をscript内で使うにはどうしたらよいでしょうか。
./script 1 2
とやると$1に1、というようになりますが、ファイルに
1
2
とあり、そのファイルを入力として渡す時はどのようにして1や2を得るのでしょうか。
0830名無しさん@お腹いっぱい。2006/03/20(月) 21:40:01
>>829
Q1 何故、findの機能を調べようとしないんだ?
Q2 何故、そのスクリプトエンジンの機能を調べようとしないんだ?
0831名無しさん@お腹いっぱい。2006/03/20(月) 22:28:06
またman読めよらしいな
0832名無しさん@お腹いっぱい。2006/03/20(月) 22:33:50
>>830,831
そういうお答えはご遠慮願います。
ちゃんとわかる方のみ、ご回答よろしくお願いします。
0833名無しさん@お腹いっぱい。2006/03/20(月) 22:38:06
>>829
一問目は、man shかman bashして、
パス名展開(Pathname Expantion) のところ読んでね。
0834名無しさん@お腹いっぱい。2006/03/20(月) 22:44:35
>>833
>>829 の1問目は、「一発で3種類のファイル数を(それぞれ)求める方法」
らしいから、それは shの「パス名展開」を読んでも解決にならないだろ。
0835名無しさん@お腹いっぱい。2006/03/20(月) 22:47:22
また「知ったかman厨」か。
0836名無しさん@お腹いっぱい。2006/03/20(月) 22:48:35
>>832
死ねよ。クズ。
08378292006/03/20(月) 22:49:10
>>830
忠告ありがとうございます。

findの方は -o -name の追加でなんとかなりました。
ファイル入力の方、ファイル名がスクリプト内で取得可能ならexecでどうこう出来る、
というのを見つけたのですが、肝心のファイル名をどうやって知ればいいのかわからんです。
なんか検索ヒント下さい。
0838名無しさん@お腹いっぱい。2006/03/20(月) 22:52:35
>>834
「それぞれ」で無くてもよかったのだけど、その場合一発で出来るんですかね。
0839名無しさん@お腹いっぱい。2006/03/20(月) 22:54:22
>>829
1問目:

「一発で」というならfindやシェルスクリプトでは無理。
3回もfindしたくないということなら、
近い方法として、
find . -name '*.c' -o -name '*.cpp' -or -name '*.cc'
の結果をシェル変数またはテンポラリファイルに一旦取り込み、
その内容を

grep '\.c$' | wc -l
grep '\.cc$' | wc -l
grep '\.cpp$' | wc -l
すればよい。


2問目:
./scriptの中で readコマンドで標準入力の内容が1行ずつ読み込める。
普通、while readみたいにして使う。
0840名無しさん@お腹いっぱい。2006/03/20(月) 22:57:06
>>838
「それぞれ」でなくていいなら、
find . -name '*.c' -o -name '*.cpp' -or -name '*.cc' | wc -l
で一発。
0841名無しさん@お腹いっぱい。2006/03/20(月) 22:59:19
このスレ的にはawkは邪道?
0842名無しさん@お腹いっぱい。2006/03/20(月) 23:02:07
スクリプト言語だからなあ。でも実際、シェルスクリプトの一部として
使われてるって現実もあるし。微妙な所か。
08438292006/03/20(月) 23:12:56
みなさんどうもありがと。

>>839
while read var
して$varを全部echoしてみたのですが、最初の値が0になっている。こういうものなの?
一つ目を無視すれば済むのだろうけど。
0844名無しさん@お腹いっぱい。2006/03/20(月) 23:18:14
>>843
おそらく、whileループの「外」でechoしてるんだろう、とエスパーしてみる。
while readする場合にはちょっと癖があって、
while文の部分がサブシェルで実行されるので、
varに値を入れても、
whileループを抜けると消えてしまう(←ちょっと不正確な表現)んだよ。
うまく工夫してそれを避けるしかない。
0845名無しさん@お腹いっぱい。2006/03/20(月) 23:19:32
じゃ、こんなのは?

find . \( -name '*.c' -o -name '*.cc' -o -name '*.cpp' \) -exec basename {} \; | \
( c=0 ; cc=0 ; cpp=0 ; while read i; do case $i in *.c ) c=`expr $c + 1`;; *.cc) cc=`expr $cc + 1`;; *.cpp) cpp=`expr $cpp + 1`;; esac; done; printf '*.c = %d\n*.cc = %d\n*.cpp = %d\n' $c $cc $cpp )

長すぎたので途中で折り返してる。
てか1行で書く必要は無いのか?
0846名無しさん@お腹いっぱい。2006/03/20(月) 23:20:04
>>843
この場合は while readを使わずに、
set `cat`
で読み込め。
これで、引数で起動したのと同じように
そのまま $1 $2 ... に代入されるよ。
08478452006/03/20(月) 23:20:14
名前消えたけど845=841です。
08488292006/03/21(火) 00:06:34
>>844
なんかよく分からないけど0が消えました。
さっき全く同じコードの筈なんだけどな。
入力ファイルの頭が0だった、なんて事は無いです。
while read var
do
echo $var
done
で0無しで動きました。不安なので再現狙ってみます。

>>845
長いからスクリプト書いた方が とか
でも一行で書けるものなんだと驚いたのも確か

>>846
うまいこと行きました。便利ですねこれ。さんくすです。


みなさんありがとうございました 
0849名無しさん@お腹いっぱい。2006/03/21(火) 00:10:20
>>829
ちょっと作ってみた

--
find . -type f | egrep '\.(c|cc|cpp)$' | \
  rev | cut -d. -f1 | rev | sort | uniq -c | sort -nr
--

egrepの部分に集計したい拡張子追加してね。
0850名無しさん@お腹いっぱい。2006/03/21(火) 00:37:22
>>849
rev | cut -d. -f1 | rev
の部分、面白いと思うけど、
プロセス3つも使うの無駄っぽいから、俺なら、

sed 's/.*\.\(.*\)$/\1/'
にするかな。
0851名無しさん@お腹いっぱい。2006/03/21(火) 00:49:35
>>850
それならもっと簡単に書ける。
sed 's/.*\.//'
0852名無しさん@お腹いっぱい。2006/03/21(火) 00:55:46
なるほどー。「man嫁」じゃなくて、ちゃんと具体例で解答すると
アイデアが膨らんで、スレのレベルが上がるねぇー。
0853名無しさん@お腹いっぱい。2006/03/21(火) 01:07:00
質問者のフォローが良かったんだな
訊き捨ての香具師にはman嫁でじゅーぶん
0854名無しさん@お腹いっぱい。2006/03/21(火) 01:41:26
スレのレベルが上がる…プッwwww
0855名無しさん@お腹いっぱい。2006/03/21(火) 01:45:48
>>849
egrep のところは find -regex を使った方がお手軽だと思う。

>>850-851 のアイディアも加えるとこんな感じ?

find . -type f -regex '.*\.\(c\|cc\|cpp\)' | sed 's/.*\.//' | sort | uniq -c | sort -nr
0856名無しさん@お腹いっぱい。2006/03/21(火) 02:41:54
-regex って、OS 依存だから、ポータブルなシェルスクリプトに
したいんだったら、egrep 使った方がいいよ。
OS 依存でいいなら構わんが。
0857名無しさん@お腹いっぱい。2006/03/21(火) 02:53:14
>>856
egrepってOS非依存か?
0858名無しさん@お腹いっぱい。2006/03/21(火) 03:35:45
もちろん非依存だよ。まあ当然 UNIX 系 OS に限るけどね。
0859名無しさん@お腹いっぱい。2006/03/21(火) 03:47:17
>>856
-regex って GNU 拡張だったんだ。
憶えておくよ。

egrep と grep -E ってどっちがポータブルなの?
0860名無しさん@お腹いっぱい。2006/03/21(火) 03:50:09
-regex は 4.4BSD 系 find にもあるから、GNU 拡張というよりは
もう少しポータブルだけどね。4.4BSD 系 OS のマニュアルには、
拡張機能だと明記してあるんだが。

egrep と grep -E では、egrep の方がポータブル。
0861名無しさん@お腹いっぱい。2006/03/21(火) 07:38:29
相変わらずラベル低いなw
0862名無しさん@お腹いっぱい。2006/03/21(火) 09:39:23
>>855,856
findの -regexがダメというなら、パイプで egrepするよりは、
find自身で -name '*.c' -o -name '*.cc' -o -name '*.cpp'
でいいと思う。ちゃんと書き直すと、

find . -type f \( -name '*.c' -o -name '*.cc' -o -name '*.cpp' \) \
| sed 's/.*\.//' | sort | uniq -c | sort -nr
かな。

findの -type fを省略していいなら、その後の \( \) も省略できる。
0863名無しさん@お腹いっぱい。2006/03/21(火) 11:19:30
ここの馬鹿どもはPOSIXとか知らんのか?
0864名無しさん@お腹いっぱい。2006/03/21(火) 11:25:04
>>863
よし、存分に語れ。
0865名無しさん@お腹いっぱい。2006/03/21(火) 11:29:26
>>863
それはそれは…是非ご教授願いたい。
0866名無しさん@お腹いっぱい。2006/03/21(火) 11:40:07
>>863
POSIX!何ですかそれは!是非ご啓示ください!!
0867名無しさん@お腹いっぱい。2006/03/21(火) 11:46:58
POSIXを読むのは有料だし、
実際の各種OSで使われているシェルやコマンドは、
POSIXと同じではない。
だから、そもそもPOSIXと同じではない各種OS間のポータビリティを
考えるなら、POSIX云々ではなく、実際に各種OSでの状況を調べて
対応するのが実践的で現実的。
0868名無しさん@お腹いっぱい。2006/03/21(火) 13:34:46
opengroup.org キタ━━━━━━(゚∀゚)━━━━━━ !!!!!
0869名無しさん@お腹いっぱい。2006/03/21(火) 14:09:32
> POSIXを読むのは有料だし、

登録は必要だけど、無料だよ。
ttp://www.unix.org/version3/online.html
0870名無しさん@お腹いっぱい。2006/03/21(火) 14:38:19
>>867
POSIX新聞?うちは取らないよ。
0871名無しさん@お腹いっぱい。2006/03/21(火) 15:47:04
>□お約束
>・特記なき場合はbourne shがデフォルトです。

今どき、bourne shをデフォルトにしているのなんて、
Solarisくらいしかないじゃん。
0872名無しさん@お腹いっぱい。2006/03/21(火) 15:54:56
>>871 Linux板に帰れ
0873名無しさん@お腹いっぱい。2006/03/21(火) 16:04:46
いや、ゴミが帰ってきても困るんだが。
0874名無しさん@お腹いっぱい。2006/03/21(火) 16:08:57
>>860
> egrep と grep -E では、egrep の方がポータブル。

嘘おっしゃい。
0875名無しさん@お腹いっぱい。2006/03/21(火) 16:09:18
du -a と find . -type f だと、やっぱり find の方が速い?
0876名無しさん@お腹いっぱい。2006/03/21(火) 16:30:18
スクリプトでは難しいけど、カレントディレクトリにあるディレクトリ数分のthreadを作ってパラレルにfind
するようなプログラム作るとめっさ速そうなんだけど。無理?
0877名無しさん@お腹いっぱい。2006/03/21(火) 16:41:16
> 嘘おっしゃい。

Linux とか POSIX の仕様しか知らない最近の人だと、そう思うかも
しれないね。SUSv3 を見ると egrep は載ってなくて grep -E だけ
が書いてあるし。

でも、もともと egrep と grep は別のコマンドで、使っているアル
ゴリズムも egrep は DFA、grep は NFA で異なっていた。10年くらい
前だと、grep に -E オプションがない OS も沢山あったよ。
これに対し、egrep はベル研 UNIX 時代から存在する由緒あるコマンド
で、事実上すべての UNIX に存在するはず。

ttp://www.bookshelf.jp/texi/autoconf-ja/autoconf-ja_10.html
> POSIX 1003.1-2001では,もはやegrepを要求していませんが,より古いホスト
> の多くはまだPOSIXのgrep -Eでの置換をサポートしていません.この問題を回
> 避するため,AC_PROG_EGREP を呼び出し,$EGREPを使用してください
0878名無しさん@お腹いっぱい。2006/03/21(火) 16:48:05
>>877
Solarisだと/usr/xpg4/bin/grepにしか-Eオプションは無くて/usr/bin/grepでは-Eは使えない。
他のOSでも使えるようにgrep -Eをスクリプトに書くのはちょいめんどくさいな。
0879名無しさん@お腹いっぱい。2006/03/21(火) 16:54:26
>>867
まずはPOSIXを読めな? ごたくはそれからだ。
0880名無しさん@お腹いっぱい。2006/03/21(火) 17:01:07
>>876
pthread使ったファイル検索プログラムがButenhofのpthread本に
載ってたような。
■ このスレッドは過去ログ倉庫に格納されています