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

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

レス数が950を超えています。1000を超えると書き込みができなくなります。
0001名無しさん@お腹いっぱい。2007/08/15(水) 07:25:02
シェルスクリプトの総合スレです。
スクリプトのお勉強・自慢・腕試しなどにどうぞ。
まずは注意点、リンク、地鎮祭など(>>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 でトレースしましょう。

前スレ
シェルスクリプト総合 その8
http://pc11.2ch.net/test/read.cgi/unix/1171517324/
0879名無しさん@お腹いっぱい。2008/02/04(月) 23:26:50
あっそ
0880名無しさん@お腹いっぱい。2008/02/04(月) 23:44:18
>>878
なぜsh互換ではNGでbash専用でないとダメなのか
その上司を問いつめて、結果をこのスレに書き込んでみ?
0881名無しさん@お腹いっぱい。2008/02/05(火) 00:49:39
おれのエスパー予想では、話題を変えようとしている>>811の涙目自演。
0882名無しさん@お腹いっぱい。2008/02/05(火) 02:11:40
>>878
まず
ttp://search.luky.org/linux-users.9/msg06102.html
とか嫁
0883名無しさん@お腹いっぱい。2008/02/05(火) 02:30:35
>>878
test とか [ を [[ 記法にでも変えたら?
0884名無しさん@お腹いっぱい。2008/02/05(火) 03:10:05
ttp://www.nicovideo.jp/watch/sm2217336
うっう〜
0885名無しさん@お腹いっぱい。2008/02/05(火) 07:15:24
>>883
testも[もないんだが、>>870 には。
0886名無しさん@お腹いっぱい。2008/02/05(火) 09:47:50
その気になればいくらでも変態的記法で書き換えられるぞ。w
こんなの趣味でも書かないけどな。w

#!/bin/bash

while read line
do
 grep "${line:0:3}" file2 &> /dev/null
 if $[ $? == 0 ] ; then
  echo "$key は file2にある"
 else
  echo "$key は file2にない"
 fi
done <<< "$( < file1 )"
0887名無しさん@お腹いっぱい。2008/02/05(火) 09:49:48
あ、間違えた。
けど、こんなの使わないからいいか。w
0888名無しさん@お腹いっぱい。2008/02/05(火) 10:19:41
互換性がなかったらシェルスクリプトの良さの3割を失なってると思うんだ…
0889名無しさん@お腹いっぱい。2008/02/05(火) 10:33:29
そうでもないよ。
0890名無しさん@お腹いっぱい。2008/02/05(火) 10:56:19
むしろ使い捨ての方が圧倒的に多いよなw
他の環境どころか、明日はもう動かなくていいやつとか。
0891名無しさん@お腹いっぱい。2008/02/05(火) 12:31:07
0892名無しさん@お腹いっぱい。2008/02/06(水) 13:18:18
$ find $HOGE -not -regex ".*#.*" -not -name "*~" -not -name "*svn*" -name "*.[ch]*"
のようなものの-not -regex ".*#.*" -not -name "*~" -not -name "*svn*"の部分だけを再利用したいんですが
ignore_backup="-not -regex \".*#.*\" -not -name \"*~\" -not -name \"*svn*\""
のようにして
$ find $FOO $ignore_backup -name "*.el"
としてもうまくフィルタリングしてくれないようです
何が良い方法はありませんか?
0893名無しさん@お腹いっぱい。2008/02/06(水) 13:33:03
evalれば?
0894名無しさん@お腹いっぱい。2008/02/06(水) 14:01:27
\"取るとか
0895名無しさん@お腹いっぱい。2008/02/06(水) 14:10:12
アドバイスありがとうございました。
evalすると言う手でなんとかしました
zsh,bashでしか確認してませんがとりあえずこんな感じでいけました
この方針なら内部で他の変数を参照する予定の無い文字列はsingle quoteにした方がよさそうですね
# dot files
ignore_bkup='-type f -not -regex ".*#.*" -not -name "*~"'
eval "$find $HOME -maxdepth 1 $ignore_bkup -regex '.*\/\..*'"
0896名無しさん@お腹いっぱい。2008/02/06(水) 14:19:36
普段は ' で、展開したい時だけ "
0897名無しさん@お腹いっぱい。2008/02/06(水) 19:47:26
質問があるのですが、
引数にlistという文字列がある場合には、lsコマンドを実行する
これを実行するにはどういう構文をつくればいいのでしょうか?
0898名無しさん@お腹いっぱい。2008/02/06(水) 20:05:04
>>897
for arg in "$@"
do
case $arg in
list)
ls;;
esac
done
0899名無しさん@お腹いっぱい。2008/02/06(水) 20:22:09
>>898
ありがとうございます
0900名無しさん@お腹いっぱい。2008/02/06(水) 23:46:40
>>898
$args → "$args"
0901名無しさん@お腹いっぱい。2008/02/06(水) 23:47:18
>>900
お前馬鹿だろ
0902名無しさん@お腹いっぱい。2008/02/07(木) 00:30:09
>>878
> 何か最低限bashシェル専用の文法を使わなければ上司が納得してくれません。

お前に必要なのは不要な文法ではなくて新しい職。
0903名無しさん@お腹いっぱい。2008/02/07(木) 04:59:08
902と意味するところは多分違うが表面的には同意。
0904名無しさん@お腹いっぱい。2008/02/07(木) 09:35:36
(1)
$ echo .string | sed -e s/^\\\\.//
.string

(2)
$ AAA=.string
$ BBB=
$ BBB=`echo "$AAA" | sed -e s/^\\\\.//`
$ echo $BBB
string


(1)(2)で結果が違ってくるのですがこれはなぜでしょうか。
0905名無しさん@お腹いっぱい。2008/02/07(木) 09:48:23
`〜`
を使っているから。
0906名無しさん@お腹いっぱい。2008/02/07(木) 09:49:18
BBB=`echo "$AAA" | sed -e 's/^\\\\.//'`
0907名無しさん@お腹いっぱい。2008/02/07(木) 09:55:55
BBB=`echo "$AAA" | sed -e s/^\\\\\\\\.//`
0908名無しさん@お腹いっぱい。2008/02/09(土) 01:16:11
BBB=`echo "$AAA" | sed -e s/^\\\\\\\\\\\\.//`
0909名無しさん@お腹いっぱい。2008/02/11(月) 14:50:12
すみません。
unixのwc -lコマンドと同等のものを
perlやawkの一行野郎にしたいのですがうまくいきません

perl -ne 'while (<>) { print cnt}' file1
お願いします
0910名無しさん@お腹いっぱい。2008/02/11(月) 14:55:30
一行野郎ってなに?
0911名無しさん@お腹いっぱい。2008/02/11(月) 14:58:34
ワンライナーのことか。
awk使いたいだけなら、
cat file1 | cat -n | tail -1 | awk '{print $1}'
でいいじゃん。
0912名無しさん@お腹いっぱい。2008/02/11(月) 15:00:28
>>911 アフォか。無駄過ぎ。いろんな意味で。
0913名無しさん@お腹いっぱい。2008/02/11(月) 15:03:27
無駄ってのは
cat file | cat -n
ってところかい?
それは最初のcatは、catじゃなくても他の部分から取れるようにしてるのだが。
0914名無しさん@お腹いっぱい。2008/02/11(月) 15:03:40
>>909
awk 'END{print NR}' file
0915名無しさん@お腹いっぱい。2008/02/11(月) 15:04:54
>>913
無駄ってのは、>>914 でできるのにわざと冗長な方法を書いていること。
0916名無しさん@お腹いっぱい。2008/02/11(月) 15:05:56
>>909をみてる感じでは、一行づつ数えたいんだと理解したのだが…。
0917名無しさん@お腹いっぱい。2008/02/11(月) 15:08:23
wc -lは複数ファイルを引数に与えられるが、そこまで同等なのか、標準入力だけでよいのか。
要求をはっきりしたまえ。

もっとも、↓これなら完璧だが。
perl -e 'exec "wc", "-l", @ARGV'
0918名無しさん@お腹いっぱい。2008/02/11(月) 15:09:44
そんなことより、>>909がなぜ行数を数えて出力できると思ったのか
みんなで考察してみようぜ。

まず、どこから急にcntが出て来たのか。
0919名無しさん@お腹いっぱい。2008/02/11(月) 15:11:25
一つのファイルだとも複数のファイルだともストリームからだとも言ってないんだから、
>>911でいいじゃないか。
思い付いたようにシンプルに済ませるのがShellScriptでしょ。
0920名無しさん@お腹いっぱい。2008/02/11(月) 15:12:23
すみません。909です。
サーバ環境のコードに合わない文字コードのファイルだと
wcコマンド使えないので他に代用したいというのが背景です。

目的はファイルの行数を単にカウントするだけです。
0921名無しさん@お腹いっぱい。2008/02/11(月) 15:18:32
何言っちゃってんの?
0922名無しさん@お腹いっぱい。2008/02/11(月) 15:28:57
と、>914さんの方法で解決できました!
みなさんありがとうございました
0923名無しさん@お腹いっぱい。2008/02/11(月) 16:58:29
やっぱり >>911 はアフォだったね。

awkなら、>>914 が解として最善だが、wcの文字コードの問題なら、
LANG=C LC_ALL=C wc -l
としても解決できるはず。
0924名無しさん@お腹いっぱい。2008/02/11(月) 17:11:58
阿呆とは思わんけど、ちゃんと情報を聞いてから答えるべきだったね。
それは>>914もそうだが。
0925名無しさん@お腹いっぱい。2008/02/11(月) 17:23:15
>>924
そんな必要ない。最初の質問情報だけで最適解を出すのが良い。
それで求めているものと違っているなら質問者が再度質問してくるだけだから。
それより問題なのは、最適解を知らないくせに質問者に追加情報だけ出せという奴。
(で、たいてい追加情報が出てきても最適解を答えられないw)
0926名無しさん@お腹いっぱい。2008/02/11(月) 17:41:27
>>925 == >>914か?
もし複数のファイルを対象にしたいとか>>914の解とは違ってたら、情報を小出
しにするなとか言い出すんだろうなw

まぁ、そんなことより追加情報が出る度に解を出して良くってのはものすごい
効率が悪いな。 最初に情報を聞き出してから普通は何かを作るだろ。
仕様が不十分なままにコード書き始めて、途中で仕様がひっくり返ったら全部
作り直しだろ。
0927名無しさん@お腹いっぱい。2008/02/11(月) 17:41:00
>>925
そのとおりだ
0928名無しさん@お腹いっぱい。2008/02/11(月) 17:45:28
ぐだぐだ言わずにとりあえずコード書けってこと?
0929名無しさん@お腹いっぱい。2008/02/11(月) 17:48:56
>>925は自分の解が最適だと思ってるのか:-)
適してるならまだしも、最適って。
別に>>911でも解としては間違ってないわけで、
なんでそんなに自分の解に自信を持ってるのかと。
0930名無しさん@お腹いっぱい。2008/02/11(月) 17:54:51
逆に、質問を変えて >>911 の解が最適になるようにしようとしてもできない。
awkを使うなら、cat -nだけでなくtail -1の機能もawk側でできるから、
わざわざ多段パイプにするのが無駄。
逆に、cat -n|tail -1にするなら、最後までawkを使わずに処理するべき。(cutとかで)
09319112008/02/11(月) 17:55:43
なんか騒いでるみたいだけど…。

perl -e 'while(<>){} print "$.\n"' file1
行数数えるだけならこうかな。

最適っていうなら、「Perlやawk」でって言ってるんだから、Perlでの最適な答えも出して上げれば良いのに。
もちろん、上の解が最適だとは思わないけどね。
他にもやり方は色々あるし、毎行処理してる時点で最適ではないし。
(awk {END}もそうだけど。)
09329112008/02/11(月) 17:56:59
>>930
awkを使って。 って書いてあるから、awkを使っただけなんだけど…。
awkはあんまり使わんから、とりあえずできればって思っただけなんだけど。
まぁ、自分はそんなに自信があって言ったわけじゃないからねスマンね。
0933名無しさん@お腹いっぱい。2008/02/11(月) 18:04:11
確かに無駄に毎行処理するのは(>>914は最後のみ実行だが、それまでも内部処理される)よろしくないな。
>>914 最適な解を望む。 最適な解だぞ。
0934名無しさん@お腹いっぱい。2008/02/11(月) 18:07:05
>>932
だから、awkを使ってっていってるのに、
なんで awk側でできる cat -n や tail -1 相当の処理を
awk側でやらないのかってこと。

>>930 の最後の行で言ってる、「最後までawkを使わずに処理するべき」ってのは、
「cat -n | tail -1」を使う以上は、ってこと。
で、それだと「awkを使う」という質問に適合しないから、
>>911 は解にならないと言いたいわけ。
0935名無しさん@お腹いっぱい。2008/02/11(月) 18:08:05
perl -lne 'END{print$.}' < file
かな。
0936名無しさん@お腹いっぱい。2008/02/11(月) 18:09:37
>>934
それだとお前の最適って言う言葉も最適ではないから解ではないな。
0937名無しさん@お腹いっぱい。2008/02/11(月) 18:14:55
元質問者は >>922 で、>>914 を使って解決したんだからそれでいいじゃん。

で、>>920 で言ってるように、本当は wc -l を使いたかったけど、
それだと日本語環境で文字コードが解釈されてエラーになるのが問題なんだから、

>>923 が言うように、
LANG=C LC_ALL=C wc -l
が最適解だね。
0938名無しさん@お腹いっぱい。2008/02/11(月) 18:18:55
tmp]$ time perl -lne 'END{print$.}' < tmp
89232

real 0m0.359s
user 0m0.327s
sys 0m0.011s
tmp]$ time perl -e 'while(<>){} print "$.\n"' tmp
89232

real 0m0.273s
user 0m0.236s
sys 0m0.010s

tmp]$ time awk 'END{print NR}' tmp
89232

real 0m0.150s
user 0m0.126s
sys 0m0.009s

tmp]$ perlcc -B tmp.pl; time ./a.out tmp
89232

real 0m0.286s
user 0m0.263s
sys 0m0.000s

やっぱりawkが早いな。
0939名無しさん@お腹いっぱい。2008/02/11(月) 18:19:55
>>937
awk, Perlを使っての解がしりたかったみたいだから、wcは最適じゃないな。
09409382008/02/11(月) 18:20:42
っていうか、バイトコンパイルしたら遅くなっちった。
0941名無しさん@お腹いっぱい。2008/02/11(月) 18:30:05
>>939
>>920 欲嫁。質問者はwc使いたかったけど使えなかったから仕方なくawkまたはperlで
ということだから、>>923 のwcが最適だね。
0942名無しさん@お腹いっぱい。2008/02/11(月) 18:35:26
コントロールコードが入ってたりしてwcが使えないのが原因だったらどうするの?
勝手に想像するのは良くないよ。
>>924欲嫁
0943名無しさん@お腹いっぱい。2008/02/11(月) 18:37:51
>>942
> コントロールコードが入ってたりしてwcが使えないのが原因だったらどうするの?

そんなのありえるの? 具体的には?
0944名無しさん@お腹いっぱい。2008/02/11(月) 18:38:27
>>942
コントロールコードが入っていても LANG=C なら wcは無問題。
実際に試してから言おうね。
0945名無しさん@お腹いっぱい。2008/02/11(月) 18:41:01
>>944
全てのコントロールコードで試したの?
そのファイルをくれないかな。
0946名無しさん@お腹いっぱい。2008/02/11(月) 18:44:45
>>945
墓穴ほってるよww

そんなの、たとえば
dd if=/dev/random bs=1024k count=1 | LANG=C wc -l

で検証できる。ファイル用意する必要なし。
0947名無しさん@お腹いっぱい。2008/02/11(月) 18:47:29
コントロールコードなら有限だから楽勝だな。
09489452008/02/11(月) 18:47:55
俺は全てのコントロールコードで試したとは言っていないが?
君が、
> 実際に試してから言おうね。
って言ったんじゃないの?
randomで出したところで、全てのコントロールコードは試してないよね。
実際に試してないのに言っちゃったの?
09499452008/02/11(月) 18:49:46
>>946
あと、それはどうやって正確に行数を数えてることを実証するの?
どこかに書き出して、自分で数えたりしてるの?
0950名無しさん@お腹いっぱい。2008/02/11(月) 18:51:27
意外に最初想像したよりもおもしろい展開になったな
0951名無しさん@お腹いっぱい。2008/02/11(月) 18:52:24
>>948
コントロールコードって、全部で32個(DELも入れると33個か?)だけって知ってる?
09529452008/02/11(月) 18:52:59
tmp]$ dd if=/dev/random bs=1024k count=1 > tmp_r

tmp]$ cat tmp_r | LANG=C wc -l
0
tmp]$ cat tmp_r | perl -e 'while(<>){} print "$.\n"'
1
tmp]$ cat tmp_r | awk 'END{print NR}'
1
tmp]$ cat tmp_r | perl -lne 'END{print$.}'
1


ものすごい影響されてるが…。
0953名無しさん@お腹いっぱい。2008/02/11(月) 18:53:37
以降、>>945 がいつまで自分の無知をさらけだすか見守りたいと思います。
0954名無しさん@お腹いっぱい。2008/02/11(月) 18:55:43
>>952
ワロタwwwwww
>>951は自分の発言すら試してなかったのか?w
それともたまたまうまくいっただけか
0955名無しさん@お腹いっぱい。2008/02/11(月) 19:00:40
>>952 では別の問題が発生してるみたいだね。
/dev/randomじゃなくて /dev/urandomでやるべき。
/dev/randomを ddで吸い出すと、十分なエントロピーがなくて
ほとんどがゼロで埋まってるものと思われ。

それとは別に、wc -lでは、最後の改行がない行を数えないが、
awk 'END{print NR}'では数えるから、行数が1ずれる。

その点は、>>945 が最初指摘していたコントロールコードの問題とは違うので、
勘違いしないように。
0956名無しさん@お腹いっぱい。2008/02/11(月) 19:04:10
>>952
だいたい、1MBも乱数で取ったのに '\n' が1つしかない時点で
その実験自体がおかしいことに気づけww 乱数になってない。
0957名無しさん@お腹いっぱい。2008/02/11(月) 19:06:04
952の人気はすばらしい
0958名無しさん@お腹いっぱい。2008/02/11(月) 19:06:49
乱数なんだから1個でどこがおかしいんだよ。
しかもファイルがおかしいにしても、今回はwcが扱えないことはわかったでしょ。
0959名無しさん@お腹いっぱい。2008/02/11(月) 19:06:53
改行コード(\n) = 1行
ということなら、この場合やはり LANG=C wc -l の計数表示が正しいということになる。
awk 'END{print NR}' では、最後の不完全な行までカウントしてしまう。

そういう意味で、やはり LANG=C wc -l が最適ということになるな。
0960名無しさん@お腹いっぱい。2008/02/11(月) 19:09:54
実験してみた。

$ echo -n a > file
$ LANG=C wc -l < file
0
$ awk 'END{print NR}' < file
1

ということだ。LANG=C wc -l の方が正しいな。
0961名無しさん@お腹いっぱい。2008/02/11(月) 19:10:33
では、>>914は自信満々だったけど正しくなかったのか。
最適とか言ってたのに残念。
0962名無しさん@お腹いっぱい。2008/02/11(月) 19:12:19
>>959
違うだろ
改行がある限り2行
0963名無しさん@お腹いっぱい。2008/02/11(月) 19:13:10
>>961
>>914 は wcを使わないという時点では最適だろ。
で、あとでwcを使わなかった理由が質問者から示されたから、
それならLANG=Cでということで、wcが最適になっただけのこと。
0964名無しさん@お腹いっぱい。2008/02/11(月) 19:13:51
定義問題だな
wcのmanではああなっているから
0965名無しさん@お腹いっぱい。2008/02/11(月) 19:14:30
では、結局新しい情報がでてきてもそれに答えられなかった>>914は最適じゃないでしょ。
次々に新しい解を出すのが>>914の言う最適な解なんだから。
0966名無しさん@お腹いっぱい。2008/02/11(月) 19:15:26
最適最適って言ってるけどさ,最適ってどういうこと?タイプ数が最小なものってこと?
0967名無しさん@お腹いっぱい。2008/02/11(月) 19:15:50
>>914に聞いてくれ。
0968名無しさん@お腹いっぱい。2008/02/11(月) 19:16:20
いいからそろそろ次スレよろ
0969名無しさん@お腹いっぱい。2008/02/11(月) 19:18:13
じゃあ>>970が次スレを立てる
0970名無しさん@お腹いっぱい。2008/02/11(月) 19:19:33
立ててきます
0971名無しさん@お腹いっぱい。2008/02/11(月) 19:25:06
シェルスクリプト総合 その10
http://pc11.2ch.net/test/read.cgi/unix/1202725267/
0972名無しさん@お腹いっぱい。2008/02/11(月) 20:25:21
このスレでダメだという指摘が出来ないものが最適。
0973名無しさん@お腹いっぱい。2008/02/11(月) 21:55:14
なんかいいスレだな。wktk
0974名無しさん@お腹いっぱい。2008/02/11(月) 22:31:36
というか、awkはスレ違い。
シェルならシェルだけでやれ。
0975名無しさん@お腹いっぱい。2008/02/11(月) 22:52:08
シェルだけでやる場合の最適解

n=0; while read dummy; do ((n++)); done < file ; echo $n
0976名無しさん@お腹いっぱい。2008/02/11(月) 23:06:41
>>975
bash依存。失格。
0977名無しさん@お腹いっぱい。2008/02/11(月) 23:33:04
じゃあこれでどう?
シェルだけということで、exprすら使わないようにしたよ

set --; while read dummy; do set "$@" a; done < file ; echo $#
0978名無しさん@お腹いっぱい。2008/02/11(月) 23:46:18
>>977
set -- はシェル実装依存。shift $# の方が確実だな。
レス数が950を超えています。1000を超えると書き込みができなくなります。