2011-12-20 22 views
1

シェルスクリプトを動作させようとしているときに、私はちょっとしたスタンパを実行しました。私は、データベースから行を読み込んで、別のソフトウェアと一緒に使用するテキストファイルにフォーマットするスクリプトを作成しようとしています。スクリプトは5千万回(大規模なデータベース)ループする必要があり、5,500回〜5,800回の繰り返しまでは問題ありません。その後、セグメント化エラーが発生します。
straceでエラーをトレースしようとしましたが(最後の数行は以下です)、私は何を見ているのか分かりません。
シェルスクリプト - セグメンテーションフォールト

clone(child_stack=0,flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD,      child_tidptr=0xb76f8728) = 17547 
close(4)        = 0 
close(5)        = 0 
pipe([4, 5])       = 0 
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD,  child_tidptr=0xb76f8728) = 17548 
close(3)        = 0 
close(5)        = 0 
pipe([3, 5])       = 0 
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0xb76f8728) = 17549 
close(4)        = 0 
close(5)        = 0 
pipe([4, 5])       = 0 
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0xb76f8728) = 17550 
close(3)        = 0 
close(5)        = 0 
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0xb76f8728) = 17551 
close(4)        = 0 
close(-1)        = -1 EBADF (Bad file descriptor) 
wait4(-1, [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], 0, NULL) = 17546 
--- SIGCHLD (Child exited) @ 0 (0) --- 
wait4(-1, [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], 0, NULL) = 17547 
wait4(-1, [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], 0, NULL) = 17548 
wait4(-1, [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], 0, NULL) = 17549 
wait4(-1, [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], 0, NULL) = 17551 
--- SIGCHLD (Child exited) @ 0 (0) --- 
wait4(-1, [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], 0, NULL) = 17550 
--- SIGCHLD (Child exited) @ 0 (0) --- 
wait4(-1, [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], 0, NULL) = 17545 
--- SIGCHLD (Child exited) @ 0 (0) --- 
write(1, "OK!\n", 4OK! 
)     = 4 
pipe([3, 4])       = 0 
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0xb76f8728) = 17552 
close(4)        = 0 
read(3, "10632\n", 128)     = 6 
read(3, "", 128)      = 0 
close(3)        = 0 
wait4(-1, [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], 0, NULL) = 17552 
--- SIGCHLD (Child exited) @ 0 (0) --- 
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0xb76f8728) = 17553 
wait4(-1, [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], 0, NULL) = 17553 
--- SIGCHLD (Child exited) @ 0 (0) --- 
write(1, "Preparing file 10632 of ", 24Preparing file 10632 of) = 24 
write(1, "51041073(7) ....", 1651041073(7) ....)  = 16 
pipe([3, 4])       = 0 
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0xb76f8728) = 17554 
close(4)        = 0 
read(3, "8\n", 128)      = 2 
read(3, "", 128)      = 0 
close(3)        = 0 
wait4(-1, [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], 0, NULL) = 17554 
--- SIGCHLD (Child exited) @ 0 (0) --- 
pipe([3, 4])       = 0 
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0xb76f8728) = 17555 
close(4)        = 0 
read(3, "", 128)      = 0 
close(3)        = 0 
wait4(-1, [{WIFSIGNALED(s) && WTERMSIG(s) == SIGSEGV}], 0, NULL) = 17555 
--- SIGCHLD (Child exited) @ 0 (0) --- 
--- SIGSEGV (Segmentation fault) @ 0 (0) --- 
+++ killed by SIGSEGV +++ 
Segmentation fault 

スクリプトは以下の通りです:情報のnoveletteため

#!/bin/sh 
#----VARS---- 
prefix="10.0.3.2/read/" 
oprdir="/home/andrew/doc/read/" 
throttle=0 

#---------------- 
x=5000 
advcount=0 
count=`curl "$prefix""count.php" 2> /dev/null` 

#----Funcs---- 
getline() 
{ 
    #Run curl to get the line of text 
    #TODO -n 
    echo -n "Preparing file" $x "of " 
    if [ $advcount -ge 25 ] 
    then 
    count=`curl "$prefix""count.php" 2> /dev/null` 
    advcount=0 
    fi 
    echo -n $count"("$advcount")" "...." 
    advcount=`expr $advcount + 1` 

    line=`curl "$prefix""testfile-prep.php?x=$x" 2> /dev/null` 
    if [ "$line" = "ERR ERROR: X OUTSIDE RECORDS." ] 
    then 
    echo "ERROR: X OUTSIDE DB... WAITING TO RETRY." 
    sleep 60 
    getline 
    fi 
    prepline 
} 

prepline() 
{ 
    echo $line | sed 's/^[0-9]*\./\n./g' | sed 's/\([a-zA-Z]*\)\./\1\n./g' | sed 's/\,/\n\,/g' | sed 's/(\(.*\)/(\n\1/g' | sed 's/\(.*\))/\1\n)/g' | sed 's/ /\n/g'> out-0-$x.dat 
    echo "OK!" 
    #cat out-$x.dat 
    advance 
} 
advance() 
{ 
    x=`expr $x + 1` 
    sleep $throttle 
    getline 
} 

cd "$oprdir" 
getline 

は申し訳ありませんが、任意の助けが理解されます。

+0

* "スクリプトは約50万回もループする必要があります" *これは私に言わなければならないコンパイルされた(またはJIT仮想マシンの)実装がこのユースケースのために良いアイデアかもしれないということです。それとも、IOバインドされていることを示すことができますか? – dmckee

+1

'prepline'関数は' sed -e 'command1' -e 'command2' ... 'を使って複数の' sed'コマンドを一つにまとめることができます。これはおそらくあなたのクラッシュとは関係ありませんが、プロセス数がかなり減ります。 –

答えて

4

あなたはstack overflowです。

getlinepreplineを呼び出します。これはadvanceを呼び出し、getlineを呼び出します。

例外のない状態で関数を呼び出すのではなく、何らかのループを使用する必要があります。 (エラーケースでの自己呼び出しは大丈夫ですが、スタックをオーバーフローさせる5,000のエラーはありません)

+0

'_繰り返しは人間です。再帰するために、神は?_ 'この場合は明らかに、どんな速度でもない。明示的な反復はどこかで問題を解決します。 –

+0

それはそれを修正するようです。なぜ私が行ったような機能を持っていたのかわからない。ありがとう! – akester

関連する問題