2011-07-31 11 views
1


私は毎日のタスクを自動化することに興味があります。最近まで、私のスクリプトのすべての部分がスムーズに実行されていました。しかし今、私はzenityを実装しようとしていて、すべてが分断されました。今私はあなたが間違っていることを見ることができることを願っています。ポイントに来複雑なbash関数:正しい使い方ですか?

スヨン、:私はこのように見て、残酷なbashスクリプトを持っている:

#!/bin/bash 

dosomething() { 
    # code 
    echo $1 >> ~/test.txt # For debugging 
    $1 & # ← Important line 
    # more code 
} 

main() { 
    # other code 
    dosomething "/usr/bin/rsync $rsync_options" # ← Call it "do_1" 
    dosomething "/usr/bin/find $findme_path -iname \"*.gpx\" -print0 | xargs -0 $other_command" # ← Call it "do_2" 
    # another code 
} 

(main | (zenity --progress $zenity_options || $still_another_command) & 

何が起こる(はずです):メインの出力は、zenityを使う(プログレスバー)にパイプされます。 mainは実際にはコマンドを実行しませんが、実行するコマンドを含むパラメータでdosomethingを呼び出します。 dosomethingはコマンドを実行します。

実際に起こること:dosomethingの「エコー」部分は期待どおりに機能します。スクリプトを実行すると、do_1とdo_2のコマンドが〜/ test.txtに正しく表示されます。 (&に端末の〜/ test.txtの内容を貼り付けた場合、すべてのコマンドが期待通りの結果で実行されました)
"do_1"の "重要な行"は期待される結果で実行されます。しかし、 "do_2"の "重要な行"は効果がないようです。少なくとも、スクリプトを実行した後は$ other_commandの効果は見えません。

私はあなたが少なくとも私が意味するものを理解することができれば幸いです。あなたが私にここで何がうまくいかないのかのヒントをくれれば、あなたのことはとても親切だろう。

+0

シバンを '#!/ bin/bash-x'に変更してもう一度実行して、出力を見てください! –

答えて

1

短い回答:BashFAQ #50を参照してください。

長い答え:bashは行を解析するときに、変数置換を行う前に引用符とコマンド区切り文字(など)を解析します。その結果、関数内で$1 &が実行され、$ 1の値の引用符とパイプは解析されず、引数の一部としてコマンド(この場合はusr/bin/find)に渡されます。 。実際の結果:実際には/usr/bin/find $findme_path -iname '"*.gpx"' -print0 '|' xargs -0 $other_command"相当のものを実行しています。

通常、このような場合は、コマンドを一連の単語として渡すことをお勧めします(つまり、関数を"[email protected]" &で実行し、それをdosomething /usr/bin/find $findme_path -iname "*.gpx" -print0と呼びますが、コマンドでパイプを処理しない場合もあります)

evalの可能性があります。evalは、大量のバグ、微妙なバグ、理解不能なスクリプトバグを作成するのに適しているため、可能な限り避けてください。バグ、セキュリティのバグなど... にすべての構文解析レイヤを追加します。これは、たとえば、という名前のファイルを操作しようとしている場合などです。それはそのアポストロフィを引用符として取り、非常に混乱します。バッククウォートを含むようになったファイルを操作することは、あまりにも恐ろしいことです。基本的には悪いニュースです。

実際のスクリプトを簡単に見てみたら、戦略の組み合わせがおすすめです。シェルの関数で複雑なコマンドをできるだけ隠すので、パイプやリダイレクトをdosomething関数を使用する場合は、先に述べた一連の単語のアプローチを使用します。実行されていますパイプ、ちょうどfind_and_do_something /whatevers/in/findme_pathの詳細はありません、あなたのログファイルを意味

#!/bin/bash 

dosomething() { 
    # code 
    printf "%q " "[email protected]" >> ~/test.txt # this gives a much better idea what's being done than echo $1 would 
    "[email protected]" & 
    # more code 
} 

# hide the pipeline in a shell function 
find_and_do_something() { 
    /usr/bin/find "$1" -iname "*.gpx" -print0 | xargs -0 $other_command 
} 

main() { 
    # other code 
    dosomething /usr/bin/rsync $rsync_options 
    dosomething find_and_do_something "$findme_path" 
    # another code 
} 

(main | (zenity --progress $zenity_options || $still_another_command) & 

を、しかし、少なくともそれは動作します:問題のスクリプトについては、私がやると思います。

+0

短い返信:ありがとう。長い返信:うわー、私はあなたがそれをやったと思う!アマチュアにとって、これは本当にうまく隠されています。よくやった!また、BashFAQをありがとう、私は多くを学んだ! – Noob

0

ここでは$other_commandを定義していますか?また、最後に末尾のかっこがないことに注意してください(mainは閉じていない括弧を開きます)。

+0

ご返信ありがとうございます。私はここに実際のコードをコピー&ペーストしませんでした。それは長すぎます。括弧を忘れて申し訳ありません。 do_2(do_somethingの後)の部分の間にパーツをコピー&ペーストしても、すべて正常に動作します。 – Noob

+0

実際のスクリプト:http://nopaste.info/b77f763cdd.html – Noob

+0

は、シェルのデバッグを有効にします。つまり、 'set -vx'です。次に、varsや他の構文が機能していないと思うかもしれません。また、いくつかの作家は '{...; }( ')の代わりに' '(' ')の代わりに' '(' ')を使います。 (各閉じる '}'の前に終端の ';'が重要であることに注意してください)幸運。 – shellter

関連する問題