• ベストアンサー

findのexecdir内でパイプを使う

現在シェルスクリプトを書いています。findの-execdirの中で次のコマンドを実行したいのですが、パイプをうまく取り扱ってもらうにはどうすればよろしいでしょうか。 tail -n +$[`sed -n "/^###END_OF_SCRIPT###$/{=;q;}" $0` + 1] $0 | tar xf - よろしくお願いします。

  • inshin
  • お礼率78% (104/133)

質問者が選んだベストアンサー

  • ベストアンサー
  • trapezium
  • ベストアンサー率62% (276/442)
回答No.2

> また、-execdirを使っているのは、検索で見つかったファイルと同一の階層に展開を行うためです。 そういうことなら find . -name foo | while read i; do (cd "${i%/*}" && tail -n +$((`sed -n "/^###END_OF_SCRIPT###$/{=;q;}" $0` + 1)) $0 | tar xf -); done とかでしょう。IFS= もした方がいいかもしれない。 > 最後に、sh -cを使うと、$0はスクリプトのパスではなくなってしまいます。^^; それか export arg=$0 として ${arg} を参照するとかでしょうか。 > ちなみに、$[]でも動きました。(bashのバージョンなどによる違い?) *BSD で単にシェルスクリプトというと /bin/sh を指します。そして *BSD の /bin/sh は bash ではありません。$[] は bash の方言というか、ある意味迷惑な代物なので、通常でも $(()) を使う方がいいと思います。 ついでに補足すると sed の {=;q;} の ; も伝統的な実装では、改行を代りに使う必要があります。 {= q } みたいに。

inshin
質問者

お礼

trapeziumさん、ご教示いただきまして、ありがとうございます。 cd "${i%/*}" && tail -n +$((`sed -n "/^###END_OF_SCRIPT###$/{=;q;}" $0` + 1)) $0 | tar xf - 先にcdしてからだと、$0が相対パスの場合、動きませんでしたので、この部分を次のようにしたらうまくいきました。 tail -n +$((`sed -n "/^###END_OF_SCRIPT###$/{   =   q }" "$0"` + 1)) "$0" | tar xCf "${i%/*}" - 確かにおっしゃる通り、bashはシステム上にある数少ないGNU由来のもののうちの一つでした。迂闊でした。 ありがとうございました。

その他の回答 (1)

  • trapezium
  • ベストアンサー率62% (276/442)
回答No.1

sh -c 経由でやるか、別スクリプトの呼び出しにするかでしょう。$0 をターゲットに置換すればいいなら、多分こんな感じ find . -name foo -execdir sh -c 'tail -n +$((`sed -n "/^###END_OF_SCRIPT###$/{=;q;}" {}` + 1)) {} | tar xf -' \; それと $[] じゃなく $(()) です。普通 $[] では演算できません。引用符の使い方に注意が必要でしょう。

inshin
質問者

お礼

trapeziumさん、ご回答いただきまして、ありがとうございます。 すみません、詳しく説明していませんでした。 まず、 tail -n +$[`sed -n "/^###END_OF_SCRIPT###$/{=;q;}" $0` + 1] $0 | tar xf - このコマンドについてですが、これは実行中のスクリプトファイル内の###END_OF_SCRIPT###に続くバイナリを特定のディレクトリに展開するためのものです。 よって、$0はスクリプトのパスになりますので、{}で置換えすることはできません。 また、-execdirを使っているのは、検索で見つかったファイルと同一の階層に展開を行うためです。 最後に、sh -cを使うと、$0はスクリプトのパスではなくなってしまいます。^^; ちなみに、$[]でも動きました。(bashのバージョンなどによる違い?) http://oxdb.hateblo.jp/entry/20110621/1308658303 こちらのサイトのコメントを参考にしました。^^

関連するQ&A

  • tail -f の出力に|(パイプ)を2回

    tail -f の出力への|(パイプ)を2回行ったものの結果が出力されず困っています。 具体的には、下記のようなコマンドを実行しています。 tail -f hoge.txt | sed -e 's/aaaa//g' | grep 'moge' 2個目のsedのみにすれば問題なく出力されるのですが、最後のgrepを行うと何も出力されなくなってしまいます。(sedの結果がgrepに渡れば必ず出力されるはずのもの) |(パイプ)の仕組みの理解が曖昧な気がしているのですが、なぜこうなってしまうのかがわかる方がいらっしゃれば教えてください。

  • bashで変数にパイプを入れ、コマンドとして使う?

    パイプを含む文字列が入った変数をシェルコマンドとして実行する方法がありましたら 教えてください。 Linux環境で、bashを使って定期的にモニタリングするスクリプトを書こうとしています。 スクリプトの引数で実行するモニタリングコマンドを変えれるようにしたいのですが、 パイプが入っているとうまくいきません。 下記のようなスクリプトで、引数に "ps -ef | grep pty" と入れたら、定期的に そのようなコマンドを実行できるようにできますでしょうか? (引数指定時に、きちんとクォーテーションで全体を囲んで、パイプが評価されない ようにしてもダメでした。) 変数として入ったコマンドを実行するときに、パイプがシングルクォーテーションで 囲まれて "ps -ef '|' grep pty" のようになってしまい、パイプとして実行時に認識 されないようです。 bashシェルで設けてる制約でしょうか?回避策などありますでしょうか? <<スクリプト poll.sh>> ## # Defs export RUNCMD='finger' export INTERVAL=10 ## # Getopt while getopts "t:" OPT; do case ${OPT} in t) INTERVAL=${OPTARG};; esac done shift $((OPTIND-1)) [ ${#} -gt 0 ] && RUNCMD="${*}" ## # Main part while :; do (set -x; ${RUNCMD}; sleep ${INTERVAL}); done

  • Java getRuntime().exec() でのパイプ利用に関して。

    はじめまして。 JavaのgetRuntime().execでコマンドプロンプトを動かそうと思っております。 コマンドプロンプトで「netstat -an | find "***"」というコマンドをJavaから実行したいと思っています。 しかし、Javaではパイプ(=|)を利用したコマンドは実行できない。 ということを検索してたどり着きました。 例などでは、「シェル」を利用しろ。などとかかれていましたが何をどうすればいいかわかりません。 String[] s = {"netstat","-an"}; Process process = Runtime.getRuntime().exec(s); 今は上記の状態で「netstat -an」が実行されています。 どうすれば「find "***"」で***の検索をかけることができるでしょうか? どうぞ、よろしくお願いいたします。

    • ベストアンサー
    • Java
  • sedでファイルで条件指定の場合

    スクリプト初心者です。 sedコマンドを使用して文字列の置換をおこないたいのですが、条件がたくさんあるため、 条件部分をシェルのファイルと別ファイルにして実行したいです。 その際、シェル実行時の引数を条件ファイルに入れたいのですが、通常の文字列扱いになってしまい困っています。 アドバイスをお願いいたします。 ・test.sh  find $1 -type f | xargs sed -i -f mypattern.sed ・mypattern.sed  s|${1}aaa|/bbb|g test.sh hoge と実行した場合 "hogeaaa" を "bbb" に置換したいです。

  • シェルスクリプトの自動化で動作が変なのですが・・・

    いつも大変お世話になります。 シェルスクリプトでtarコマンドを書き、このファイルをcrontabで自動化しております。 設定した時間になるとcrontabが実行され、ファイルが生成されるのですが、ファイル容量が少なく、tarコマンドがきちんと実行されていない様なのです。 あるディレクトリをまるごと圧縮しているのですが、容量は1GB程あり、これを tar czvf /directory_name1/file_name1.tar.gz /directory_name2/ というコマンドで圧縮しております。 直接このコマンドを実行するとちゃんと圧縮され、約940MBの容量になります。しかし、crontabでシェルスクリプトを実行すると45バイトのファイルが生成されて終ってしまいます。 なぜなのか、さっぱり原因が分かりません。 どなたかご教授の程、何卒、宜しくお願い致します。

  • シェルのリダイレクトとパイプについて

    シェルのリダイレクトとパイプについての質問です. リダイレクトでコマンドの標準出力をファイルに指定した後に, パイプを置いて,もう一つコマンドを並べたとき, 後の方のコマンドの標準入力はどうなるのでしょうか? 例えば, ls >outfile |cat ならば, catの標準入力には,何も入ってこないと思うのですが, これを実行すると,lsの結果がoutfileに書き込まれ, 次のプロンプトが表示されます. 普通,catを引数なしで実行すると, EOFが入力されるまで,入力待ちになると思うのですが, こうならないのは,シェルがcatの標準入力にEOFを入力したからだと 考えていいのでしょうか. よろしくお願いします. (質問の意味が分かりにくければご指摘下さい.)

  • "パイプが切断されました"の表示を出したくない

    自作シェルスクリプト | less とやったときlessを中断すると "パイプが切断されました"というエラーが発生します。 恐らく親プロセスの出力が完了する前にlessを終了した場合に発生するのだろうと考えているのですが、自作スクリプトを修正して、このエラーを出さないようにすることはできますか。 自作スクリプトは次のような繰り返し処理になっていて時間がかかるため、中断された場合を考慮した作りにしたいです。 find | while read FILE do 処理 done

  • wshでDOSコマンドを利用するには。 パイプ処理

    http://www.okweb.ne.jp/kotaeru.php3?q=305516 の続きです。 wshでDOSコマンドのnetstat -nの値をメッセージボックスで表示するには、次のスクリプトの”コマンド”の部分にnetstat -nを入れることで可能です。 (FlossenEngel 様作成) ------------------------------------- Set WshShell = WScript.CreateObject("WScript.Shell") Set objExec = WshShell.Exec("コマンド") Do While objExec.Status = 0 WScript.Sleep(100) Loop sout = "" Do While Not objExec.StdOut.AtEndOfStream sout = sout & objExec.StdOut.ReadLine & Chr(13) & Chr(10) Loop MsgBox sout ----------------------------------------------- さて、netstat -n|find " ESTABLISHED" というぐあいに パイプ処理を行うにはどうすればよいでしょうか? Set objExec = WshShell.Exec("netstat -n|find " ESTABLISHED" ") とするとエラーになります。 "を入れ子にできないようですね。 解決方法ご存知の方おしえてくださいませ。

  • find結果で文字列検索?

    RedHatLinux7.2です。 シェルコマンドで複数のテキストファイルからある文字列を含むファイルだけリストアップしたいのですが、文字列検索の対象となるテキストファイルが色々なディレクトリにまたがっている場合はどうやってやればよいでしょうか? 多分findで抽出したファイルパスをgrepに渡せばいいんでしょうけどパイプとか?がまだ不勉強ですぐにわかりません。 初歩的なことだと思いますがよろしくお願いします。

  • 複数あるファイルの中から、あいうという文字が入っているファイルを検索するバッチを教えてください。

    dir /s とfindとパイプでしょうか?またシェルスクリプトならどうなるでしょうか 補足お返事ありがとうございます。やってみましたが、何もおきませんでした。