トップページ⇒linux
988コメント336KB

シェルスクリプト総合@LINUX Part3

■ このスレッドは過去ログ倉庫に格納されています
0001login:Penguin2007/07/10(火) 23:17:13ID:qGthZdME
UNIX板のスレを見ている方も多数おられるかと思いますが、
まあそれはそれとして、BASHウゼーとか言われる心配なく
平和にLINUX的スクリプト談義しましょうよ。

初めての自作スクリプト、自信ないから見てください。な初心者から
トリッキーな技を駆使した作品を披露したい、蘊蓄を語りたい上級者まで
いろいろな人に参加して頂けると嬉しいです。

perlやらPythonやらの話が混ざっても良いんでない?

【sed】シェルスクリプト総合@LINUX Part2【awk】
http://pc11.2ch.net/test/read.cgi/linux/1154578200/
http://pc8.2ch.net/test/read.cgi/linux/1121994321/

>>2-5あたりに色々と。
0683login:Penguin2008/02/25(月) 12:48:54ID:fTf5K0mT
同一内容のファイルを調べるシェルスクリプトなんだけど、過去にここかUNIX板の方で出てたっぽい。
結局やらず仕舞いだったようだし、どうせならシェルスクリプトの勉強がてらやってみようとおもった。

作りたい理想は以下のとおり
 ・コマンドラインでオプション指定を行い、検索ディレクトリとサブディレクトリへの再帰検索をするかどうか、あとファイルサイズ閾値を指定できる
 ・走査しているディレクトリにあるファイルパス&ファイルサイズのペアをリストとして吐く
 ・ファイルサイズ閾値未満で、ファイルサイズが一致したものに対してmd5sumを実行し、両方が同一のハッシュを吐いた場合、表示する。
 ・ファイルサイズ閾値を設定する理由はmd5sumが時間がかかりそうだから。閾値以上のサイズ一致ファイルはmd5sumすることなく表示する。

0684login:Penguin2008/02/25(月) 12:52:01ID:fTf5K0mT
ちなみにサブディレクトリの再帰検索をせず、指定したディレクトリの全てのファイルのハッシュ値を比較して表示するだけなら

#!/bin/sh
md5sum $1/* | uniq -D --check-chars=32 | sed 's/^[0-9a-f]* \*//g'

上のだけで済むかな。標準エラーがうざいけど・・・
まずはディレクトリの再帰検索について質問したいところです。
0685login:Penguin2008/02/25(月) 12:55:37ID:fTf5K0mT
あ、uniqの間にsortを入れてあげるとより親切か
うちの場合はwgetで自動保存したファイルの整理だから、ファイル名が必然的に「DLファイル名+.連番」だから気にならないけど
まったく違うファイル名かつ内容は同一ってときに、ハッシュ値でsortしてあげていた方がいいよね
そう考えたらsedでハッシュ値をわざわざ消す必要もないか・・・

md5sum $1/* | sort | uniq -D --check-chars=32
0686login:Penguin2008/02/25(月) 12:57:54ID:fTf5K0mT
再帰検索はこの場合、find $1でファイルリストを列挙してからreadで"ls->ファイルサイズ取得"やら"md5sum"やらした方がいいのかな?
0687login:Penguin2008/02/25(月) 13:38:12ID:fTf5K0mT
不恰好だけどサブディレクトリまで調べて、全てのファイルにmd5sumして表示するのはこんな具合か・・・

#!/bin/sh
TMPFILE="filelist"
touch $TMPFILE
find $1 | while read FILENAME; do
if [ -f "$FILENAME" ]; then
md5sum "$FILENAME" >> $TMPFILE
fi
done
sort < $TMPFILE | uniq -D --check-chars=32
rm $TMPFILE

もうちょっとスマートにならないかなあ・・・ あとユニークなサイズのファイルはmd5sumさせたくないなあ
0688login:Penguin2008/02/25(月) 13:47:58ID:pu40lUxS
書いてみた。

#!/bin/sh
# finddup.sh -- find . | finddup.sh
while read -r FILENAME
do
    [ -f "$FILENAME" ] &&
        printf "%14d:%s\n" `stat -c %s "$FILENAME"` "$FILENAME"
done | sort | uniq -D -w14 | cut -b 16- |
xargs md5sum | sort | uniq -D -w32
0689login:Penguin2008/02/25(月) 13:53:38ID:pu40lUxS
uniq -f のほうが良さそうだね
0690login:Penguin2008/02/25(月) 13:57:12ID:ATO0A7OZ
>>687
find . -type f -print0 | xargs -0 md5sum | sort | uniq -D -w32
0691login:Penguin2008/02/25(月) 14:17:36ID:fTf5K0mT
>>688
ありがとう!
あ、ただファイルやディレクトリ名にスペースが入るとmd5sumにしっかり渡せないみたいです
bash on cygwin環境だとWindowsの「コピー (2) 〜 hoge.txt」という名前が恨めしい

>>690
出力結果同じだΣすげえ
ちょっとman読んでこよう・・・
0692login:Penguin2008/02/25(月) 14:23:38ID:pu40lUxS
xargs --delimiter "
" md5sum
でどうかな。ちゃんとテストしなきゃだめだね
まあ改行文字を含むファイルがあるとだめなんだけど、面倒だから他の言語でやらせたほうがいい
0693login:Penguin2008/02/25(月) 14:26:43ID:ATO0A7OZ
>>692
>>690
0694login:Penguin2008/02/25(月) 14:27:32ID:pu40lUxS
>>693
全部のファイルにmd5sumかけたら遅いだろ
0695login:Penguin2008/02/25(月) 14:31:42ID:fTf5K0mT
あ、>>688のxargs md5sumを>>690のようにxargs -0 md5sumにすればOKなのかな
0696login:Penguin2008/02/25(月) 14:38:34ID:ATO0A7OZ
>>695
んで、printf 側でも \n じゃなく \0 を使うようにする。
0697login:Penguin2008/02/25(月) 14:39:51ID:pu40lUxS
uniqとcutはどうするよ
0698login:Penguin2008/02/25(月) 14:43:11ID:fTf5K0mT
printfで囲ってやればイケました(`・ω・´)

#!/bin/sh
# finddup.sh -- ./finddup.sh target-path
find $1 | while read -r FILENAME
do
[ -f "$FILENAME" ] &&
printf "%14d:\"%s\"\n" `stat -c %s "$FILENAME"` "$FILENAME"
done | sort | uniq -D -w14 | cut -b 16- | xargs md5sum | sort | uniq -D -w32
0699login:Penguin2008/02/25(月) 15:21:01ID:zYqxhFYE
久々にまともな流れだな
0700login:Penguin2008/02/25(月) 16:57:52ID:fTf5K0mT
ついでに以下のような動きが出来ないか色々試してみています。
どうも二進も三進も行かない

$ ./findup.sh ~/pic/jun.2chan.net/

2件の一致ファイル:8f7c1e2adb45adbfdb4d86adb1b9e894--------------------------
~/jun.2chan.net/b/src/1192805081129.jpg
~/jun.2chan.net/b/src/1192805081141.jpg
-------------------------------------------------------------------------------
~/jun.2chan.net/b/src/1192805081129.jpgを削除しますか?[y/N/a]
~/jun.2chan.net/b/src/1192805081141.jpgを削除しますか?[y/N/a] y
~/jun.2chan.net/b/src/1192805081141.jpgを削除しました。

3件の一致ファイル:6fc4bdc4bc3bb06882bc98d9cbeb60c3--------------------------
~/jun.2chan.net/b/src/1192800164913.jpg
~/jun.2chan.net/b/src/1194189136460.jpg
~/jun.2chan.net/b/src/1194189137115.jpg
-------------------------------------------------------------------------------
~/jun.2chan.net/b/src/1192800164913.jpgを削除しますか?[y/N/a] y
~/jun.2chan.net/b/src/1192800164913.jpgを削除しました。
~/jun.2chan.net/b/src/1194189136460.jpgを削除しますか?[y/N/a] y
~/jun.2chan.net/b/src/1194189136460.jpgを削除しました。

↑同一として列挙されたパスの残りが1になると削除せず次へ
0701login:Penguin2008/02/25(月) 17:00:46ID:ATO0A7OZ
>>700
そこまで行くとシェルスクリプトには荷が重いんじゃないか?
0702login:Penguin2008/02/25(月) 17:10:48ID:fTf5K0mT
>>701
以下の点でハードルがあがってるみたいですね

・一致したファイルのグループ分け
・ファイルを一つだけ残して削除した場合、残りの1ファイルは削除しない

列挙した全ファイルに対して、質問→削除というのは簡単にいけそうな感じ。
自分の知識だけで無理と判断して投げるのはアレだと思ったんだけど、やっぱ難しいかなあ
0703login:Penguin2008/02/25(月) 18:09:02ID:pu40lUxS
#!/bin/bash
# askdelete.sh -- find . | finddup.sh | askdelete.sh
# よくテストされてませんので注意
TMPF=`mktemp /tmp/askdelete.XXXXXX`
trap 'rm $TMPF' 0
CURHASH=
COUNT=0
(cat; echo DUMMYHASH /dev/null) |
while read -r HASH FILENAME; do
    if [ "$CURHASH" ] && [ "$CURHASH" != "$HASH" ]; then
        echo "------------------------------"
        echo "$COUNT 件の一致ファイル:$CURHASH"
        tail -n $COUNT $TMPF | cut -b 33-
        echo "------------------------------"
        tail -n $COUNT $TMPF | while read -r HASH FILENAME; do
            [ $COUNT -eq 1 ] && break
            echo -n "$FILENAME を削除しますか? [yN] "
            while read ANSWER
            do
                case "$ANSWER" in
                [yY]) echo rm "$FILENAME"
                      COUNT=`expr $COUNT - 1` ;;
                esac
            done < <(head -1 /dev/tty)
        done
        COUNT=0
    fi
    echo $HASH $FILENAME >>$TMPF
    CURHASH=$HASH
    COUNT=`expr $COUNT + 1`
done
0704login:Penguin2008/02/25(月) 18:12:29ID:pu40lUxS
done < <(head -1 /dev/tty) とか、絶対おかしいよこれ。
違う言語で書き直したほうがいい。
0705login:Penguin2008/02/25(月) 18:17:46ID:fTf5K0mT
おおすげええΣ
ちょっとテストしてみます!
0706login:Penguin2008/02/25(月) 19:20:15ID:pu40lUxS
#!/bin/sh
# askdelete.sh -- find . | finddup.sh | askdelete.sh
TMPF=`mktemp /tmp/askdelete.XXXXXX`
trap 'rm -f $TMPF' 0 1 2 3 15
CURHASH=
COUNT=0
(cat; echo DUMMYHASH /dev/null) |
while read -r HASH FILENAME; do
    if [ "$CURHASH" ] && [ "$CURHASH" != "$HASH" ]; then
        echo "------------------------------"
        echo "$COUNT 件の一致ファイル:$CURHASH"
        tail -n $COUNT $TMPF
        echo "------------------------------"
        tail -n $COUNT $TMPF | while read -r FILENAME; do
            [ $COUNT -eq 1 ] && break
            echo -n "$FILENAME を削除しますか? [yN] "
            while read ANSWER; do
                case "$ANSWER" in
                [yY]) echo rm "$FILENAME"
                      COUNT=`expr $COUNT - 1` ;;
                esac
                break
            done < /dev/tty
        done
        COUNT=0
    fi
    echo $FILENAME >>$TMPF
    CURHASH=$HASH
    COUNT=`expr $COUNT + 1`
done
すこしよくなった
参考になる http://www.nurs.or.jp/~asada/FAQ/UNIX/section3.8.html
0707login:Penguin2008/02/25(月) 20:58:36ID:NDOa2UbC
理想的な流れだ。
0708login:Penguin2008/02/26(火) 01:26:57ID:Knz7qJ2h
>>706
サブシェルをわざわざ使う必要は無いのでは?

--- (cat; echo DUMMYHASH /dev/null) |
+++ { cat; echo DUMMYHASH /dev/null; } |
0709login:Penguin2008/02/26(火) 01:31:17ID:V2S90oTo
こんなのじゃ駄目?

find . -type f -print | xargs md5sum | sort | while read i
do
 set -- $i
 test -e .$1 && rm -i $2
 touch .$1
done

削除して残りが1つなら消さずに次、ということは最初の1つは
無条件で残して、2つ目以降についてのみ rm -i で削除確認すれば
いいんだよね?

記憶用に .<md5sum> なマーカ作ってるけど、ここは md5sum な
ダミー環境変数の方がいいかも。
0710login:Penguin2008/02/26(火) 08:30:35ID:V4Ca66lJ
>>709
全ファイルにmd5sumしたら遅くならない?
0711login:Penguin2008/02/26(火) 08:46:21ID:M2OUW+0j
>>708
パイプを使うと結局はサブシェルが起動されるんだから () のほうがわかりやすいと思うよ
0712login:Penguin2008/02/26(火) 09:53:07ID:jk2VB7eG
>>710
どうせシェルスクリプトなんて使い捨てなんだし
多少遅くてもいいんじゃない?
実行時間の長さより
思いついたことをちゃちゃっと実行できる手軽さが大事でしょ。
0713login:Penguin2008/02/26(火) 10:56:04ID:V4Ca66lJ
>>712
もっともな意見だと思うが、肝心なことを棚に上げてるな
シェルスクリプトの本質は処理を効率化するための機能なんだから、
手軽に加えて「より早くスマートに処理」できる方がいいだろうよ

どうせ使い捨てとか言い出したら、いつまで経っても遅くて低機能なスクリプトしか書けないぜ?
まあせっかくいい方向で流れてるから、俺も最適化してみるか。
0714login:Penguin2008/02/26(火) 15:09:02ID:KrvpwwSS
手作業で30分かかる作業を、わずかワンライン5秒で済ます。
どうよ、この快感、すごいよ、俺!!
ただしスクリブト書きに3時間かかるけどなっ!!、
みたいな・・・・
0715login:Penguin2008/02/26(火) 15:18:25ID:jk2VB7eG
5分で書いて実行時間3分にできればそれでおkだよな。
その作業を200回繰り返さなきゃいけないなら
3時間かけて書いて5秒に短縮してもいいけど、
そういうのはシェルじゃなくて別な言語を使った方がいいと思う。
0716login:Penguin2008/02/26(火) 16:04:42ID:V4Ca66lJ
>>714
良いスクリプトを早く書けるスキルを養うといった考えはないのかよw
まぁ価値観が違うなら仕方ないが

>>715
言いたいことは分かるし仕事では俺も同じスタンスだ。モトが取れない作業をするのはアホだと思う。
さらに>>1にあるようにPerlやPythonを使ってもいいと書いてあるように、別にシェルスクリプトに固執はしてないさ。
ただID:fTf5K0mTみたいに質問を丸投げせずに分かってないながらも自分で試してみている奴も居るんだから
「どうせ使い捨て」や「パンがなければケーキを」じゃなくて、しっかりした見本を見せてやろうぜw・・・と思ったんだ。

勝手に限界を作っちゃダメさ・・・!
0717login:Penguin2008/02/26(火) 17:08:11ID:KrvpwwSS
頑張るところが・・・まっいっか。人それぞれだな。
0718login:Penguin2008/02/26(火) 17:30:17ID:DxWnmOPN
>>717
茶化すだけならWindowsに切り替えてフリーソフトスレにでも行け。
同一ファイル発見ソフトなんていくつもあるから。
自分で作ろうと思わん奴はウザイだけだ。
0719login:Penguin2008/02/26(火) 22:37:31ID:ecwr7n8r
Windowsに切り替えて同一ファイル発見ソフトを探すってのもこれまた手間だよな
0720login:Penguin2008/02/27(水) 00:57:44ID:k4ecn/gW
ああそういう意味か。
Linuxならawkでもperlでもpythonでもgccでも大概入ってんだろうになんで
>Windowsに切り替えてフリーソフトスレにでも行け
なのかマジで理解できなかった。
なるほどな、そういう考え方もあるか。これは考えが及ばなかったな。
まぁうちext3だしなぁ。
0721login:Penguin2008/02/27(水) 02:09:44ID:5Pe1iZtE
>>711
サブシェル一個より分かりやすさを重視、ってのも分かるが
プロセスを fork するコストはバカにできないぞ。
たった 10 回でもこれだけ差が出る。

$ time for i in 0 1 2 3 4 5 6 7 8 9 ; do { :; } ; done
real 0m0.001s
user 0m0.010s
sys 0m0.000s

$ time for i in 0 1 2 3 4 5 6 7 8 9 ; do ( :; ) ; done
real 0m0.221s
user 0m0.140s
sys 0m0.140s

今回のはともかく、ループの中で無駄なサブシェル起こすと
かなり処理速度に効いてくるから、「より早くスマートに処理」を
目指すなら気にした方がいいと思うよ。
0722login:Penguin2008/02/27(水) 12:04:07ID:5xPFitgJ
>>721
そうじゃなくて、パイプではサブシェルが起動されるでしょう?
$ { FOO=foo; echo $FOO; } | cat
foo
$ echo $FOO
$
0723login:Penguin2008/02/27(水) 23:04:12ID:6K2aGQ5h
>>722
popenってfork & execvじゃなかったっけ?
0724login:Penguin2008/02/28(木) 01:04:44ID:2c894vLr
$cat a001
abc

$cat a002
def

$cat a003
ghi

という内容の連番ファイルがあるときに、
a001,a002,a003ファイルそれぞれの先頭に
自身のファイル名を追記していくにはどのようにすればいいでしょうか?

$cat a001
a001
abc

$cat a002
a002
def

$cat a003
a003
ghi
0725login:Penguin2008/02/28(木) 01:27:48ID:k7I0oIXn
for a in *; do
echo $a > temp
cat $a >> temp
mv temp $a
done
0726login:Penguin2008/02/28(木) 01:53:39ID:2c894vLr
>>725
できましたありがとうございます!!
0727login:Penguin2008/02/28(木) 11:40:05ID:xnWdeCI1
csvの編集をしているのですがカンマを含むデータがある場合に特定の列を削除するいい方法はないでしょうか?

例:
編集前) aaa,bbb,"ccc,ddd","eee",ff

編集後) aaa,"ccc,ddd",ff

カンマを含むデータは必ずダブルクォーテーションで囲まれているのですが
どの列にカンマを含むデータが存在するかは不明です。
192の方法だと特定の列は出せるのですが、複数列を表示することができないので。。。
0728login:Penguin2008/02/28(木) 11:45:53ID:sfXUxgeO
>>727
シェルスクリプトでがんばるより↓あたり使ったら?
http://blog.livedoor.jp/dankogai/archives/50765677.html
0729login:Penguin2008/02/28(木) 12:17:28ID:DWKM9TyE
>>727
無駄にがんばってみた。PerlとかSQLiteとか使った方が絶対いい。
#!/usr/bin/awk -f
BEGIN {OFS=",";}
function csplit(s,a,c,f,i,j,k){delete a;for(i=j=1;;i++){
c=substr(s,i,1);if(c==""){a[k++]=substr(s,j,i-j);break;}
else if(c=="\""){if(f>0){if("\""==substr(s,i+1,1))i++;
else f=0;}else f=1;}else if(c==","&&f==0){a[k++]=substr(s,
j,i-j);j=i+1;}}return k;}
{n=csplit($0,array);print array[0],array[2],array[4];}
0730login:Penguin2008/02/28(木) 20:37:03ID:VzdvBwjj
吐きそうだ。
字下げを知らないやつがまだこの世にいたのか。
0731login:Penguin2008/02/28(木) 20:53:53ID:k7I0oIXn
>>730
じゃあお手本をちょっと見せてくれ
0732login:Penguin2008/02/28(木) 22:39:21ID:VzdvBwjj
死ぬまで>>729記法で頑張りゃいいんじゃね?
それも個性だ。
0733login:Penguin2008/02/28(木) 22:40:23ID:gxJgMbC8
敗北宣言はええ
0734login:Penguin2008/02/29(金) 00:47:32ID:1XKkNNaQ
2ch に貼る時気をつけないと空白スペース詰められちゃうよね
0735login:Penguin2008/02/29(金) 01:30:01ID:Pgw8LnNi
そこで&nbsp;
0736login:Penguin2008/02/29(金) 01:41:57ID:bnE90VmD
行末にタブがある行を検索しようと
egrep '\t$'
としてもマッチしません。awkだと
awk '/\t$/'
でマッチするのですが、grepだとどう書けばいいのでしょうか?
0737login:Penguin2008/02/29(金) 01:59:08ID:Pf9U77bc
元々、\tなどのメタキャラクタはgrepにもawkにもなかった。
GNU awkがPerlの影響を受けて拡張しただけ。
0738login:Penguin2008/02/29(金) 02:10:07ID:bnE90VmD
そうなのかー・・・ちょっとしょぼーん。拡張されてもいい感じなんだけどね。
grep sed awk ぐらい正規表現は統一して欲しかったorz
0739login:Penguin2008/02/29(金) 08:36:03ID:qSBWA6nK
タブを¥tと書きたかった理由が
シェルからコマンドラインにタブを打とうとして補完機能に取られるから、
であれば、Ctrl-V TAB でたぶんOK。

0740login:Penguin2008/02/29(金) 09:40:38ID:HrPH8ECW
くだ質からこちらに誘導されたので、こちらで質問させて下さい。

ド素人質問で悪いのですが

$ cat text1.txt
1
2
3

$ cat text2.txt
3
4
5

という二つのファイルがあるとして、それを1行ずつ割り算したいのです。
結果としてこういう形になれば満足です。

$ cat result.txt
0.33
0.50
0.60

どのように記述すれば良いのでしょうか、シェルは普段bashを使っていますが、
もちろんshでも構いません。宜しくお願いします。
0741login:Penguin2008/02/29(金) 09:42:18ID:/PNY/URb
>>740
ぱっと思いついたもの。

( echo 'scale=2' ; paste -d/ text1.txt text2.txt ) | bc
0742login:Penguin2008/02/29(金) 09:48:46ID:HrPH8ECW
>>741
早速ありがとう御座います。こんな結果になりました。

.33
.50
.05
(standard_in) 5: parse error
53
4
5

pasteってこういうときにも使えるんですね。
parse errorとかbcとか知らないものも調べてみます。
07437402008/02/29(金) 09:58:48ID:HrPH8ECW
>>741
すいませんでした、エラーは自分の不備によるものでした。
きちんと結果表示されたので満足しています。ありがとう御座いました。
0744login:Penguin2008/02/29(金) 10:03:24ID:Mcdovrgg
スクリプトで2台のDebian間を rcp でコピーしようと思っています。
expect を使って、スクリプトを作成し、それがうまく動作するところまでは
こぎつけたのですけれど、cronに登録すると動かなくなってしまいます。。。。

どうすれば解決するでしょうか?アドバイスをいただけると嬉しいです。

ちなみにスクリプトは
==========================-
#!/bin/sh

expect -c "
set timeout 20
spawn rcp -r {コピー元} {コピー先}
expect sword:\ ; send \"{パスワード}\r\"
"
==============================
こんな感じです。

ご教授のほどよろしくお願いします。



0745login:Penguin2008/02/29(金) 10:04:13ID:/PNY/URb
>>744
カレントディレクトリがどこになってるのか、とか
権限に問題はないか、とか。

つーか rsync あたり使った方が楽じゃない?
0746login:Penguin2008/02/29(金) 17:16:24ID:HrPH8ECW
シェルスクリプトでは無いのかもしれませんが、今日2度目の質問をさせて下さい。。
スレ初心者なので、スレ違いだったらすいません。

LPIC試験の勉強のために初めてjoinコマンドを使うのですが、うまくいかず困っています。
1.txtと2.txtに、1〜999999の中から任意に500個程度選び出した数字を
それぞれフィールド1に、その他データをフィールド2以降に並べた
テキストファイル(↓こんな感じにソートしたのものです)

$ cat 1.txt    $ cat 2.txt
50 aiu       50 abc 1111
80 eoka      140 def 2222
↓         ↓
999999 wawon  531243 xyz 3333

があるのですが、フィールド1に同じ数字が書かれた行を
joinで繋げたいんです。色んなサイトやLPICの勉強本を参考にしたのですが

$ join -1 1 -2 1 1.txt 2.txt
$ join -j 1 1.txt 2.txt

上の2つでは、300個くらいHITするはずなのですが、数個しか出てきません。
全く同じ行に同じ数字がフィールド1に入っているものだけが出力されているようです。
行数が数行しかないファイルではきちんと違う行でも結合してくれるのですが、
行数が多いとjoinでは無理ってことはありますか?
500行くらい処理してくれるものだと思ったんですが・・・泣。
シェルスクリプトでうまくいくのであればヒントを下さい、シェルはbashです。
0747login:Penguin2008/02/29(金) 17:21:26ID:/PNY/URb
>>746
いまいちやりたいことがわからん。
5行くらいのファイルで例示してみてくれ。

しかし join なんて使ったことないな。
そんなん知らなくても実務ではまったく困らん。
perl かなんかで書く勉強でもした方が役に立つよ。
0748login:Penguin2008/02/29(金) 17:52:51ID:HrPH8ECW
>>747 
初めて学ぶスクリプト言語をシェルスクリプトにしようと決めたところでして、
perlとかは全く知らないんです・・・。ですが実務ではなく趣味なので楽しんでいます。
それと説明が下手ですいません(泣)再度説明させて下さい。

$ cat join1.txt
157 A B
160 C D
1291 I J
1373 K L

$ cat join2.txt
157 C D
160 E F
1373 K L

この2つのファイルをフィールド1個目でくっつけて
$ join -j 1 join1.txt join2.txt
157 A B C D
160 C D E F
1373 K L K L

にしたいんですが(上のファイルだとくっつきました)、各フィールド数が7個
各行数が500行程度、各ファイルサイズは30KBくらいになると、フィールド1個目の
数字が一緒でも、行が1個でもずれているとくっつかなくなり、行が同じものしか結合しなくなりました。
joinの精度が低いのが原因なのだとしたらお手上げなのですが、
何か他の原因は思いつきますでしょうか。perlとかSQLは全く無知なのでシェルで済ませたいんです。
07497462008/02/29(金) 18:07:44ID:HrPH8ECW
自己解決したわけではないのですが、やっぱり精度の問題みたいです・・・。
>>748の join1.txt と seq 150 200 > seq1.txt でjoinコマンドを使ってみたら結合できましたが
>>748の join1.txt と seq 1 2000 > seq2.txt でjoinコマンドを使ってみたら1つも結合出来ませんでした。
何か他の工夫で切り抜けたいと思います・・・失礼しました。
0750login:Penguin2008/02/29(金) 21:29:21ID:d0BiI2Kq
>FILE1 と FILE2 は実行前に join フィールドの昇順にソートしておかなければならない(数値順のソートはだめ)。
だとさ。


0751login:Penguin2008/03/01(土) 06:54:44ID:+XEPxk54
月に一度、メールログを調べたいのですが、
下記スクリプトを毎月1日朝に走らせています。

---
#!/bin/sh
pre_month_days=`date -d '1 days ago' +%d`
zcat /var/log/maillog.{1..$pre_month_days}.gz | 引き渡し先プログラム
---

これをシェルで走らせると
zcat: /var/log/maillog.{1..29}.gz: No such file or directory
となります。

ですが、
#zcat /var/log/maillog.{1..29}.gz
と手打ちすると、ズシャーっとログが表示されます、エラーも最後まで出ません。

変数展開されていないならまだしも、まったく原因がわかりません。
どういう理由で「No such file or directory」が出るのでしょうか?
0752login:Penguin2008/03/01(土) 07:04:36ID:5EZ+WSHA
変数が入ってると{}って展開されないんじゃね?
0753login:Penguin2008/03/01(土) 10:33:04ID:t3ZBWfKh
x=29
echo {1..$x}
してみようぜ。
07547512008/03/01(土) 17:46:18ID:IgLZSOLf
>>752-753
{1..29}

・・・ってことは、{1..29}そのものを探す=「No such file or directory」
ってことでしょうか?

ということは、pre_month_daysの文だけfor文で回して、
$temp_textにためていってから、解析プログラムに引き渡すと今思ったのですが、

この$temp_textというのは、シェルスクリプトが終了したときには、
消えてなくなるのでしょうか?どこかに残っているものなのでしょうか?
$temp_textだと、120万行ぐらいあるので、どこかに残っていれば圧迫しかねませんし・・・。
07557512008/03/01(土) 19:12:07ID:IgLZSOLf
す、すいません、
bashのfor文ってわけわかりません、( )とか{ }とか使うと思っていたのですが・・・。


zcat /var/log/maillog.$x.gz >> $temp
を繰り返して、

引き渡しプログラム $tempとしたいのですが、
for文(他のやり方もある?)をどう使えばいいのでしょうか?
0756login:Penguin2008/03/01(土) 19:37:33ID:t3ZBWfKh
for文はCみたく配列を添え字でループするのと違って、
並べた要素1つ1つに対してループするというもの。

for x in 1 2 3 4 5; do
echo $x
done
とかな。

1から先月末日までの日の並びを作るために、Linuxならおそらくseqが使える。
# BSDだとjot

for $x in `seq $pre_month_days`; do
zcat ...$x...
done
とか。
0757login:Penguin2008/03/01(土) 20:11:24ID:quX+uZMv
bash なら
for (( i = 0; i < 10; i++ )); do
echo $i
done
みたいな C っぽい for 文も使える。
07587512008/03/01(土) 20:32:55ID:IgLZSOLf
>>756-757
seqを使ってもエラーが出るので、
Cっぽくやってみました。

aaa.1.txt
aaa.2.txt
aaa.3.txt

を用意して、

------------------
#!/bin/bash
x=3
temp=""
for (( i=1 ; i < $x+1; i++ )); do
cat aaa.$i.txt >> $temp
done
cat $temp
-------------------

./test2.sh: line 5: $temp: ambiguous redirect
./test2.sh: line 5: $temp: ambiguous redirect
./test2.sh: line 5: $temp: ambiguous redirect

マズー(;´Д`)

am・big・u・ous[ mbjus ]
[形]
1 2通り(以上)の解釈を許す
2 (正体の)あいまいな;紛らわしい;はっきりしない, ぼんやりした, もうろうとした, おぼろげな

0759login:Penguin2008/03/01(土) 20:49:48ID:pGgAUYn5
temp=""

書き込み先がないじゃんか。

temp=nulpo.txt

とか書き込み先がないと。
07607592008/03/01(土) 21:51:32ID:IgLZSOLf
い、いけました。
1ヶ月のメールログ1.4GBを食わせることができました。
ありがとうございます。
0761login:Penguin2008/03/01(土) 22:39:09ID:pGgAUYn5
>>760

最初の>751をよく見てなかったんだけど、maillog.*がそんなに多くない(毎月かならず1〜29になっている、てので)なら

for file in `ls /var/log/maillog.*`
do
zcat $file | 処理プログラム
done

でいいのでは。

それと焦って名前欄間違えないように〜w
07627602008/03/01(土) 23:08:45ID:IgLZSOLf
あぅ、すいません。
logrotateはdailyの120でcompressなんです。
で、月次解析なんで、

その日の前日の「日にち」を取って、
zcatしなくちゃならなかったんです。

でも、これで月次の解析ができます〜
0763login:Penguin2008/03/02(日) 03:30:36ID:b0TlSvfI
いい流れた
0764login:Penguin2008/03/02(日) 22:17:28ID:eyDRtewQ
>>760
ファイルに落とさない方法もあるぞ
引き渡し先がワンパス処理で無い場合は失敗する可能性
があるのでおすすめ出来ないが...

#!/bin/sh
pre_month_days=`date -d '1 days ago' +%d`

( for i in `seq 1 $pre_month_days` ; do
printf "/var/log/maillog.${i} "
done ) | xargs echo zcat | 引き渡しプログラム

exit $?
##
0765login:Penguin2008/03/03(月) 09:55:39ID:4ARrqAXS
括弧はいらないね
0766login:Penguin2008/03/03(月) 13:44:09ID:WtSCj+5U
>>751
eval zcat /var/log/maillog.{1..$pre_month_days}.gz | 引き渡し先プログラム
0767login:Penguin2008/03/03(月) 23:36:12ID:5ghxiELA
んー
簡単なApacheログ解析&集計用スクリプト組みたいんだけどシェルスクリプトだとパフォーマンス悪いかな?
RubyやPythonは使えないんで、bash系シェルスクリプトかPerlでやってみたいんですが

ちなみにログフォーマットはこんな感じ
mxxxxxx.dynamic.ppp.asahi-net.or.jp - - [27/Feb/2008:15:46:04 +0900] "GET / HTTP/1.1" 200 101323 "http://hoge.piyo/" "Opera/9.25 (X11; Linux i686; U; ja)"
1リクエストに対して1行記録され、日付毎にファイルがある。(ファイル名の例:access_log_20080227)

465日分で容量2.5GB超とちょっと多いです。
やりたいことは項目別のランキングをテキスト出力だから、スクリプト自体は簡単そう
0768login:Penguin2008/03/03(月) 23:43:14ID:Zrc2Vdg0
それはanalogとかでできないものでしょうか(´-`)
0769login:Penguin2008/03/03(月) 23:46:01ID:5ghxiELA
>>768
実はそんな気がしてた
ありがとう('`)〜♪
0770login:Penguin2008/03/04(火) 00:34:34ID:61UoHuE3
ウワー早い
2分ちょいでこれだけ解析できるのかー
ああでも肝心なRefererランキングが出てないわ
Analogスレは4ヶ月近く誰も居ないみたいだしドウシタモンダカー
0771login:Penguin2008/03/04(火) 09:48:48ID:kUaxbjJj
Bashを使ってシェルスクリプトの練習をしています
ファイルに特定の文字列が記載されていたら処理を分岐させるというシェルを書きたいと思っているのですがなかなか上手くいってくれません
何かいい方法がありましたら教えていただけないでしょうか

やりたい事はファイル内にHTMLという文字列が入っていたらAの処理 入っていなかったらデフォルトの処理をしたいと考えたので
下記のようにしてみました

TMP=`cat $YEAR$MONTH$DAY.csv |grep HTML`;
echo $TMP
case "$TMP" in
HTML)echo "HTML file"
;;
*) echo "##################"
esac

0772login:Penguin2008/03/04(火) 09:54:01ID:oWYbuV9h
>>771
if grep HTML "$YEAR$MONTH$DAY.csv" >/dev/null; then
echo "HTML file"
else
echo "##################"
fi
0773login:Penguin2008/03/04(火) 14:33:52ID:kUaxbjJj
>>772
ありがとうございます
教えていただいた通りにやったら問題なくできました

なぜcat|grepのときは上手くできなくて
grepの時は問題なくできるのかがちょっと分からないのですが
いろいろ調べてみようと思います


0774login:Penguin2008/03/04(火) 21:04:44ID:rsD9V5Zj
HTML) を *HTML*) としてみようぜ。

0775login:Penguin2008/03/04(火) 23:06:20ID:VrfR3qUe
>>774
やだよ
0776login:Penguin2008/03/05(水) 00:05:43ID:EV9xTscM
grep -q を使わないのはポータビリティー重視だから?
0777かね ◆CHAS.7AvVo 2008/03/05(水) 10:22:08ID:JQ4a1dor?2BP(158)
>>777ゲット
0778login:Penguin2008/03/10(月) 18:08:47ID:qsIz6iXz
論文を書くときに使うグラフをTopazというソフトを用いて作成しております。
その結果、グラフがepsファイルとして作成されるのですが、Windowsにもってくるとフォント関係でエラーが生じてしまいます。
なのでLinuxでフォントをアウトライン化しようと思い「eps2eps」というコマンド(シェルスクリプト?)を用いて
epsファイルのフォントをアウトライン化しました。
しかし、そうするとbounding boxがおかしくなってしまいます。
ですので元のepsをテキストエディタで開き、bounding boxの項目をコピペして対応しています。



それでようやく本題なんですがw
上のような作業を、複数のファイルに対して一括で行いたいのです。

for file in *.eps
do
eps2eps $file ${file%eps}2
done

のようなシェルスクリプトを使えば一括でアウトライン化epsができると思うのですが
さらに、インプットファイルをテキストエディタで開きbounding boxの項目をコピー
アウトプットファイルにbounding boxの項目を貼り付け
というような機能を持たせることはできるのでしょうか?
0779login:Penguin2008/03/10(月) 19:47:47ID:PtxOKuxD
ed
0780login:Penguin2008/03/11(火) 02:26:04ID:3Mwu+R1S
>>778
スクリプトに慣れた人ならすぐに作れる。
0781login:Penguin2008/03/12(水) 23:51:51ID:wAPdko8t
>>780
?
0782login:Penguin2008/03/13(木) 22:58:09ID:A7XLS93G
>>781
!
0783login:Penguin2008/03/13(木) 23:17:56ID:SoJCaJfU
ああ、無情
■ このスレッドは過去ログ倉庫に格納されています