シェルスクリプト総合 その8
■ このスレッドは過去ログ倉庫に格納されています
0001名無しさん@お腹いっぱい。
2007/02/15(木) 14:28:44スクリプトのお勉強・自慢・腕試しなどにどうぞ。
まずは注意点、リンク、地鎮祭など(>>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 でトレースしましょう。
前スレ
シェルスクリプト総合 その7
http://pc10.2ch.net/test/read.cgi/unix/1157601611/
0176名無しさん@お腹いっぱい。
2007/03/03(土) 17:55:22その実装の違いを推測してるのではないか? なので、おかしくない。
ちなみに俺の環境では、kshでもtestよりcaseの方が速かったよ。
0177名無しさん@お腹いっぱい。
2007/03/03(土) 18:59:530178名無しさん@お腹いっぱい。
2007/03/03(土) 20:43:22real 0m1.758s
user 0m1.562s
sys 0m0.160s
bash3 case
real 0m1.515s
user 0m1.341s
sys 0m0.150s
確かに少しだけど、case の方が速いね
0179名無しさん@お腹いっぱい。
2007/03/03(土) 20:53:55いや、[[じゃなくて [ と caseを比較するという話だが。
速い順に、
case > [[ > [
となると思う。
0180名無しさん@お腹いっぱい。
2007/03/03(土) 21:13:01あ、そうだったっけか。
bash3 [
real 0m2.388s
user 0m2.042s
sys 0m0.370s
0181名無しさん@お腹いっぱい。
2007/03/04(日) 21:32:58ディレクトリ名とその中にあるファイルサイズが0のファイル名を出力する。
補足1:ディレクトリが特定されていない場合は、現在シェルが働いているディレクトリ名を出力する。
補足2:もし引数がディレクトリ名でない場合は、すべてのコマンドラインの引数にエラーメッセージを出力する。
補足3:ファイル名の一番最初の文字が、「.」の場合は無視するようにする。
0182名無しさん@お腹いっぱい。
2007/03/04(日) 21:54:16問題に曖昧なところがあるけど、こういうことか?
bashじゃなくてもB-sh共通で動く。
dir=${1-.}
if [ ! -d "$dir" ]; then
echo "$dir is not a directory" 1>&2
exit 1
fi
for f in "$dir"/*
do
if [ ! -s "$f" ]; then
echo "$f"
fi
done
0183名無しさん@お腹いっぱい。
2007/03/04(日) 21:55:25大体こんな感じじゃない?
usage() {
echo "Usage: ..." 1>&2
exit 1
}
test -d $1 && find $1 -not -name '\.*' -size 0 -print || usage()
ただし補足1はGNU findの機能を使ってるので、どのfindでもということなら
$1が空だった場合の扱いを自分でする必要がある。あと、「.」で始まる
フォルダは処理したいのなら、find の条件をもうちょっと詰める必要がある。
0184名無しさん@お腹いっぱい。
2007/03/04(日) 21:59:310185名無しさん@お腹いっぱい。
2007/03/04(日) 22:01:31レスありがとうございます。
問題文は元々英語の為、変な訳になって細かい部分が伝わらず申し訳ありません。
英文ですが、元の問題はこちらです。ttp://user.ftth100.com/log/up/log/3569.gif
0186181
2007/03/04(日) 22:21:53分かりやすい解説付でありがとうございます。
この場合、
test -d $1(ディレクトリ名を引数1に格納)
&& find $1 -not -name '\.*' -size 0(ファイル名の頭文字が「.」、サイズが0の物をはじく)
-print || usage() (結果をusage()に返し、出力)
usage() で、正常ならば結果を出力。エラーならば1>&2が働きエラーを表示。そしてexitで終了。
といった感じでしょうか?
0187名無しさん@お腹いっぱい。
2007/03/04(日) 22:46:22この問題って出所はどこなの?
0189名無しさん@お腹いっぱい。
2007/03/04(日) 23:23:20>>181 のいう通りなので、後は自分で解読してみてください。
0190名無しさん@お腹いっぱい。
2007/03/04(日) 23:24:060191名無しさん@お腹いっぱい。
2007/03/05(月) 14:36:49短絡評価でぐぐれ
0192名無しさん@お腹いっぱい。
2007/03/05(月) 15:46:28sed -n '/^[yn][eo]/p;s/^IPアドレス.//p' data.txt | fmt -w 18 | tr ' ' ,
0193192
2007/03/05(月) 15:55:14yes/no 個別に書くべきですね。
それとスペースを数えると正しくは fmt -w 19 だ ww
0194192
2007/03/05(月) 16:14:27スレ汚し済まない。
0195名無しさん@お腹いっぱい。
2007/03/05(月) 16:49:38perl -ne 'BEGIN { $/ = "----\n" } /(yes|no).*(\d+(?:\.\d+){3})/s && print "$1,$2\n"'
0196名無しさん@お腹いっぱい。
2007/03/05(月) 17:46:13sed -f 135.sed
$ cat 135.sed
/^----/{N
s/^----\n//
x
d
b
}
/^IPアドレス /{
s/IPアドレス /,/
x
G
s/\n//
b
}
d
0197名無しさん@お腹いっぱい。
2007/03/07(水) 17:04:39一行ずつ一つのログファイルに延々と結果が記載されます。
100
ABC
101
200
DEF
201
…こんな感じで3行ずつが一連のアクションです。
これを以下のように整形したいのですが、妙案は有りますでしょうか?
100,ABC,101
200,DEF,201
ご教示いただければ幸いです。
0198名無しさん@お腹いっぱい。
2007/03/07(水) 17:29:18sed 'N;N;s/¥n/,/g'
む、あたまに余計な空行が付くな。
0199名無しさん@お腹いっぱい。
2007/03/07(水) 17:31:060200名無しさん@お腹いっぱい。
2007/03/07(水) 18:03:28やっぱりsedを使うのかな?と思い本を見ていたところでした。
なるほどNで行数分読み込んで、改行\nを,に置き換える…。
見れば直ぐに解りますが、これを0から考えるのは大変でした。
今度は誰かに教えれるよう、頑張ります。
素早いご解答ありがとうございました!
0201名無しさん@お腹いっぱい。
2007/03/08(木) 12:24:02利用者が指定した文字列の書いてあるファイルを読み込んで、
配列に文字列を一つずつ格納し、その文字列を順番に出力させたいのですが、
どのようにすれば良いのでしょうか?
0202名無しさん@お腹いっぱい。
2007/03/08(木) 12:32:35どのシェルよ?
少なくともピュアBourneシェルには配列はない。
0203名無しさん@お腹いっぱい。
2007/03/08(木) 12:33:26申し訳ありません。bashです。
0204名無しさん@お腹いっぱい。
2007/03/08(木) 12:37:11tr ' ' '¥012' < ユーザーが指定したファイル | sort
という意味?
指定したファイルの中はどんな構造なの?
1行に1語なのか、フリーテキストか。
0205名無しさん@お腹いっぱい。
2007/03/08(木) 12:40:27指定したファイルは、おっしゃる通り、1行1語のテキストファイルです。
Sapporo
Tokyo
Osaka
Nagoya
Fukuoka
といった感じです。
単純に中身を表示するだけなら、
echo -n "ファイル名を入力してください:"
read x
cat $x
でよいと思われるのですが、一度配列に全文字列を格納してやるので困っています…。
0206名無しさん@お腹いっぱい。
2007/03/08(木) 12:46:39sort そのファイル
とするのとは違うの?
0207名無しさん@お腹いっぱい。
2007/03/08(木) 12:55:10sort ファイル とは違い、この場合だと、
array[0]=Sapporo
array[1]=Tokyo
array[2]=Osaka
array[3]=Nagoya
array[4]=Fukuoka
i=0
while [$1 -le 5]
do
echo ${array[$i]}
let i=$i+1
done
読み込んだテキストファイルをこのような感じで出力させたいです。
0208名無しさん@お腹いっぱい。
2007/03/08(木) 12:58:490209名無しさん@お腹いっぱい。
2007/03/08(木) 13:05:51シェルスクリプトじゃなきゃいかんの?
perlかなんか使った方が楽じゃない?
0210名無しさん@お腹いっぱい。
2007/03/08(木) 13:12:43「整列させて」という意味ではないことは理解した。
0211名無しさん@お腹いっぱい。
2007/03/08(木) 13:16:34words=($words $word)
done < 指定したファイル
してあとは一緒。
0212名無しさん@お腹いっぱい。
2007/03/08(木) 13:43:20perlじゃ駄目なんです。
>>211
echo -n "ファイル名を入力してください:"
while read word; do
words=($words $word)
done < $word
という事でしょうか?
0213名無しさん@お腹いっぱい。
2007/03/08(木) 14:02:360214名無しさん@お腹いっぱい。
2007/03/08(木) 14:07:43すいません・・・
どうやれば良いのでしょうか?
0215名無しさん@お腹いっぱい。
2007/03/08(木) 14:10:26echo -n "ファイル名を入力してください:"
read source
while ....
done < $source
あとは出力のためのループ
0216名無しさん@お腹いっぱい。
2007/03/08(木) 14:52:24echo -n "ファイル名を入力してください:"
read source
while read word; do
words=($words $word)
done < $source
cat $source | while read
do
echo $words
let source=$source+1
done
でやってみましたが、テキストの最初の文字列しか表示されません。
後半の出力ループがいけないのでしょうか?
0217名無しさん@お腹いっぱい。
2007/03/08(木) 15:06:490218名無しさん@お腹いっぱい。
2007/03/08(木) 15:12:44代わりに一パラメータで逃げてみた。
while read word; do
set -- $* $word
done < $source
for word in $*; do
echo $word
done
0219名無しさん@お腹いっぱい。
2007/03/08(木) 15:18:07×一パラメータ
○位置パラメータ
あんど、こう書くらしい。
while read word; do
size=${#words[@]}
words[$size]=$word
done < $source
for word in ${words[@]}; do
echo $word
done
0220名無しさん@お腹いっぱい。
2007/03/08(木) 15:24:40↓
http://pc11.2ch.net/test/read.cgi/linux/1154578200/
ここはBourneのみでよろしこ。
0221名無しさん@お腹いっぱい。
2007/03/08(木) 15:49:17動作確認出来ました。本当にありがとうございました。
>>220
誘導ありがとうございます。
スレ違いで申し訳ありませんでした。
0222名無しさん@お腹いっぱい。
2007/03/08(木) 15:53:31教えてください
#!/bin/sh
COUNTER=0
while [ $COUNTER -lt 100 ]; do
mv "$COUNTER".jpg /home/more/
let COUNTER=COUNTER+1
done
こんな感じのとき最初の10までが1桁になってしまうのですが
01 02 03,,,,
行頭に0を付けた2桁で処理するのはどうすれば良いのでしょうか?
00-09と10-99でループをわけるしか無いのでしょうか?
0223名無しさん@お腹いっぱい。
2007/03/08(木) 15:59:51mv `printf %02d $COUNTER`.jpg /home/more
なければ
mv `echo "0$COUNTER" | sed 's/0*¥(..¥)$/¥1/'`.jpg /home/more
とか、
mv `echo "0$COUNTER" | rev | cut -b1,2 | rev` /home/more
とか。
0224名無しさん@お腹いっぱい。
2007/03/08(木) 16:09:12for COUNTER in `seq -w 0 99`; do : ...; done
↑でループすれば桶。
あと、letコマンドは純粋な shには無いぞ。
0225名無しさん@お腹いっぱい。
2007/03/08(木) 16:11:22そもそもループすら不要で、
mv [0-9][0-9].jpg /home/more
だけで一発。シェルは不要。
0226名無しさん@お腹いっぱい。
2007/03/08(木) 16:11:480227名無しさん@お腹いっぱい。
2007/03/08(木) 16:12:07ありがとうございました。
最終行でうまくいきました。
上の2個も含め手法を理解するように勉強してみます
0228名無しさん@お腹いっぱい。
2007/03/08(木) 16:15:29ので不要じゃないわよ>>225
0229名無しさん@お腹いっぱい。
2007/03/08(木) 16:16:49お約束どおり釣れましたよ。おめでとう。
0230名無しさん@お腹いっぱい。
2007/03/08(木) 16:18:58ありがとう。
実際にはdateから自動生成された莫大な
画像データを部分的に抽出しながら動画生成を
行うので
例に出したのより多少複雑に書き直します
seqも実験してみます
0231名無しさん@お腹いっぱい。
2007/03/08(木) 16:20:11[root@localhost /tmp]$ ls
[0-9][0-9].txt
となります。
00.txtから99.txtを作りたいのですが…
0232名無しさん@お腹いっぱい。
2007/03/08(木) 16:20:180233名無しさん@お腹いっぱい。
2007/03/08(木) 16:23:11zsh -c 'touch {00..99}.txt'
とか
0234名無しさん@お腹いっぱい。
2007/03/08(木) 16:26:04どういう結果になってほしいんだろう。
0235名無しさん@お腹いっぱい。
2007/03/08(木) 16:27:16は、書かれてしまったから
touch `seq -s ".txt " -w 99"`.txt
0236名無しさん@お腹いっぱい。
2007/03/08(木) 16:27:590237名無しさん@お腹いっぱい。
2007/03/08(木) 16:28:4900.txtから連番で99.txtまでのファイルが欲しいんでしょ
0238名無しさん@お腹いっぱい。
2007/03/08(木) 16:30:36いつものお約束も釣れましたよ。おめでとう。
0239名無しさん@お腹いっぱい。
2007/03/08(木) 16:31:170240名無しさん@お腹いっぱい。
2007/03/08(木) 16:35:08ありがとうございました!
zshって凄いですね。
でも、それに依存しないよう
>>235さんの方法を覚えます。
0241名無しさん@お腹いっぱい。
2007/03/08(木) 16:38:39exprを使うのが定石。
expr 0$COUNTER : '.*\(..\)'
0242名無しさん@お腹いっぱい。
2007/03/08(木) 16:40:100243名無しさん@お腹いっぱい。
2007/03/08(木) 16:43:230244名無しさん@お腹いっぱい。
2007/03/08(木) 16:46:42seq -f %02g.txt 0 99
の方がエレガント。
0245名無しさん@お腹いっぱい。
2007/03/08(木) 16:53:02-sは間に挟む文字列だから最後の.txtがないと、
00.txt ... 98.txt 99 で終わってしまうぞ。
でも正解は>>244。
0246名無しさん@お腹いっぱい。
2007/03/08(木) 16:57:54確かにこっちなら完璧に出来ますね。
ところで %02g と言うのは何なんでしょうか?
0247名無しさん@お腹いっぱい。
2007/03/08(木) 17:06:19man seq
つーか
man 3 printf
0248201
2007/03/08(木) 18:43:31最後にもうひとつだけ質問させてください。
出力をする時に配列の反対(リバースオーダー)から出力をするのはどうやれば良いのでしょうか?
例えば、
Tokyo
Osaka
Nagoya
とあったら
Nagoya
Osaka
Tokyo
と出力されます。
0249名無しさん@お腹いっぱい。
2007/03/08(木) 18:46:19tac
0250名無しさん@お腹いっぱい。
2007/03/08(木) 18:51:21done | tac
のようにパイプすればいいのではないでしょうか。
tacがない環境では、
for ...
done | sed '1!G;h;$!d'
0251201
2007/03/08(木) 19:14:20これでなんとか単位が取れます
0252名無しさん@お腹いっぱい。
2007/03/08(木) 19:25:380253名無しさん@お腹いっぱい。
2007/03/08(木) 19:46:300254名無しさん@お腹いっぱい。
2007/03/09(金) 00:33:46↓みたいに書いてみたのですがエラーでちゃいます。なぜ??
#!/bin/csh
set ALLCOUNT = 5
@ CT = 1
@ NO = 3
@ CN = ""
while ( $NO <= $ALLCOUNT )
set CN[$CT] = `sed -n "$NO p " job.txt
@ CT ++
@ NO ++
end
0255名無しさん@お腹いっぱい。
2007/03/09(金) 01:11:36配列を使おうと思った時点で負け。別の方法を探すべし。
0256名無しさん@お腹いっぱい。
2007/03/09(金) 01:17:09>>201と同じ学校の人?
0257名無しさん@お腹いっぱい。
2007/03/09(金) 01:19:14ダメっぽ?
>256
いや趣味
0258名無しさん@お腹いっぱい。
2007/03/09(金) 07:50:56それが宿題だとすると、そんな教官がいるような学校に
進学した時点で負け。
0259名無しさん@お腹いっぱい。
2007/03/09(金) 07:52:390260名無しさん@お腹いっぱい。
2007/03/09(金) 07:54:46cshで書かなければいけない合理的な理由は存在しない。
趣味なら自分で研究すること。
0261名無しさん@お腹いっぱい。
2007/03/09(金) 17:07:470262名無しさん@お腹いっぱい。
2007/03/09(金) 19:22:220263名無しさん@お腹いっぱい。
2007/03/09(金) 21:47:41所詮人間がデータ構造を解釈しているだけの話。
0264名無しさん@お腹いっぱい。
2007/03/10(土) 21:31:59というより口だけで実は分からないだけですかおまいら。
0265名無しさん@お腹いっぱい。
2007/03/10(土) 21:37:01宿題かどうかが問題なんじゃなくて、cshのスクリプトは論外ということ。
誰も答えるはずがない。
0266名無しさん@お腹いっぱい。
2007/03/10(土) 21:44:390267名無しさん@お腹いっぱい。
2007/03/10(土) 21:45:26__l // / | \ \\ ゙、 / ̄ ̄ ̄ ̄ ̄ ̄
/ :::|| / / / l l ヽ ヽヽド、 /
l::::::::::|| / / / ! l ヽ ヽ ヽヽ ||:::::ヽ | l 十`` 十_ヽ
斤.::::::::||/ / //! ハ l ! ヽ ', ゙ヽ||::::::::勺 | レ d、 (_| _)
|ll|i :::::::|| l l イ l /!l | ヽ ト、|、 ト、 l l、||::::::::}ll| | ┼‐、ヽ ┴┴
|ll|ヽ:::::|l !l |l!‐!‐ト、l ヽ | l | ヽ | l i l l||:::::::/!l| | ノ 月 l |
|lll| `ー! l | l 」-=ミ|`ヽ ヽ | !-‐!‐|-l、|} l |r、〃|ll| | 二二`` l__ヽ
L!l | l | 〃{ノ::::iヾ ヽ! ,. =-ミ、!ハ l !"´ |ll| | ノ _)
{l |!l | ヽ `ー" ' トイ:::}ヾ | l | |ll」 | ─ァ
ヽ |l !| `二ノ '| || | /\
l |', | /)|l l | ┼‐、ヽ
l | ゙、 ` ´ /-イ| l | ノ
!| \ ヽニヽ , ′/゙! l ∠ '⌒)
| |ヽ、 ー / 〃 | ! | 「
,.rr| 丶、 ,.. '´ト、 l′ ヽ ゚
l::l {:| ` ´ |::}} \______
_. -‐1::ヽ' -、 _,.. -‐ン::|ヽ、
_.. -‐ "´ |:::::::::`ゝヽ /rJ::'"´:::::::! ` 丶、
0268名無しさん@お腹いっぱい。
2007/03/10(土) 21:52:540269名無しさん@お腹いっぱい。
2007/03/10(土) 22:04:010270名無しさん@お腹いっぱい。
2007/03/10(土) 22:11:17毎回、問題を出すのにネタが尽き気味で大変です。
宿題が出た人、どんどんその問題を書き込んでください。
一部変えて出題に使わせていただきます。
0271名無しさん@お腹いっぱい。
2007/03/10(土) 22:19:470272名無しさん@お腹いっぱい。
2007/03/10(土) 22:29:26分かった。
うちで使うスクリプトを問題として出してやる。
0273名無しさん@お腹いっぱい。
2007/03/12(月) 10:34:35tacをシェルスクリプトで書かせる。
0274名無しさん@お腹いっぱい。
2007/03/12(月) 10:47:03そういえば、まだ bash の回答がない。
ttp://golf.shinh.org/p.rb?reverse+lines
この問題にかぎらず、sh で参戦してる人が少ないのでおまいらもやってみてくれ。
おれもがんばってみる。
0275名無しさん@お腹いっぱい。
2007/03/12(月) 17:31:24何も無理してshだけで文字列操作するこたーないと思うけど。
#!/bin/sh
f () { local l; read -r l && { f; echo "$l"; }; }
f
■ このスレッドは過去ログ倉庫に格納されています