web-dev-qa-db-ja.com

find-execでawkを使用する

3列形式(タブで区切られた)のデータを含むファイルの束を含む14個のディレクトリを持つディレクトリ構造があります。 findとawkを使用して、これらの各ファイルから2番目の列を抽出し、同じファイル名で異なるルートフォルダーに出力するつもりでした。ここに私のディレクトリのスケッチがあります。

data/all-> AA、AB、AC、AD ...(A *は、AA100.txt、AA101.txtなどの3列形式で保存されたデータを含むファイルを含むフォルダーです...)

同じ名前の変更された(1列の)ファイルが必要ですが、すべて新しいルートディレクトリにありますdata/pos(data/all /ではなく)-> AA、AB、AC、AD ...(再び、それぞれにA * 100.txt、A * 101 ...が含まれています)

Find -execを使用してawkコマンドを実行しようとしましたが、ファイルを適切な場所に出力する際に​​問題が発生します。

データ/すべて/にあるとき

find * -type f -exec awk '{print $ 2}' '{}'> ../ pos/'{}' \;

ただし、入力ファイルのワイルドカードとしての{}は、ファイルを出力するときに機能しないようです。

私は何が間違っているのですか? (私はubuntuサーバーにいます)

4
conipo

必要なのがすべてのファイルである場合は、検索せずに試すことができます。 data/all/にいる間に、これを実行します。

for file in ./*; do awk '{print$2}' "$file" > "../pos/$(basename $file)"; done

/data/allの下の階層全体のファイルをカバーしたい場合、bashを使用している場合はglobstarオプションを有効にして(これはzshで「うまくいく」と思います)、**を使用してすべてのファイルを照合できます:

shopt -s globstar
for file in ./**; do awk '{print$2}' "$file" > "../pos/$(basename $file)"; done
3
Jacobo de Vera

私は何が間違っているのですか?

リダイレクト> ../pos/'{}'findまたはawkによって処理されたかのように使用していますが、リダイレクトはシェルによって処理されます。あなたの場合、それはfind全体の出力のみをリダイレクトできることを意味します(awkの出力はリダイレクトできません)。

通常、findの開始パスに*のようなワイルドカードを使用する必要はないことに注意してください。一般的な方法はfind .でしたか、それともfind *の理由はありますか?

ソリューション

ここでは、Jacobo de Veraによるソリューションとは対照的に、findの柔軟性を維持します。シェルループでawkを実行します。

find . -type f -print0 |
  while read -r -d $'\0' x; do
    awk '{print $2}' "$x" > "../pos/$(basename "$x")"
  done

-execを使用した元の方法は、すべてのファイルに対してawkに加えてシェルが起動され、マルチレベルのエスケープがここではかなり複雑になるため、効率が低下します。

find . -type f -exec sh -c 'awk "{print \$2}" "{}" > "../pos/{}"' \;

awk内でリダイレクトを行う別の解決策もあります。

6
pabouk