14

GNU parallel多くのファイルをWebサーバーに投稿するために使用しようとしています。私のディレクトリには、いくつかのファイルがあります。

file1.xml
file2.xml

そして、私は次のようなシェルスクリプトを持っています:

#! /usr/bin/env bash

CMD="curl -X POST -d@$1 http://server/path"

eval $CMD

スクリプトには他にもいくつかありますが、これは最も単純な例です。次のコマンドを実行しようとしました。

ls | parallel -j2 script.sh {}

これは、GNU parallelページがディレクトリ内のファイルを操作する「通常の」方法として示しているものです。これはファイルの名前をスクリプトに渡すようですが、curl は渡されたデータ ファイルを読み込めないと文句を言います。

find . -name '*.xml' | parallel -j2 script.sh {}

それは正常に動作します。引数をスクリプトに渡す方法lsとの間に違いはありますか? findまたは、そのスクリプトで何か追加する必要がありますか?

4

4 に答える 4

9

GNUparallelは のバリアントですxargs。どちらも非常によく似たインターフェースを持っていparallelますxargs

そうは言っても、どちらも操作方法はかなり単純です。デフォルトの動作では、両方のプログラムが STDIN から入力を読み取り、空白に基づいて入力をトークンに分割します。これらの各トークンは、提供されたプログラムに引数として渡されます。xargs のデフォルトでは、できるだけ多くのトークンをプログラムに渡し、制限に達したときに新しいプロセスを開始します。並列のデフォルトがどのように機能するかわかりません。

次に例を示します。

> echo "foo    bar \
  baz" | xargs echo
foo bar baz

デフォルトの動作にはいくつかの問題があるため、いくつかのバリエーションが見られるのが一般的です。

最初の問題は、トークン化に空白が使用されるため、空白が含まれるファイルがあると、並列および xargs が破損することです。1 つの解決策は、代わりに NULL 文字をトークン化することです。findこれを簡単にするオプションも提供します。

> echo "Success!" > bad\ filename
> find . "bad\ filename" -print0 | xargs -0 cat
Success!

この-print0オプションはfind、空白の代わりに NULL 文字でファイルを区切るように指示します。
この-0オプションはxargs、NULL 文字を使用して各引数をトークン化するように指示します。

parallelデフォルトの動作が改行のみをトークン化するという点よりも少し優れていることに注意してくださいxargs。したがって、デフォルトの動作を変更する必要はほとんどありません。

xargsもう 1 つの一般的な問題は、引数がまたはに渡される方法を制御したい場合があることですparallel。プログラムに渡される引数の特定の配置が必要な場合は、 を使用{}して、引数を配置する場所を指定できます。

> mkdir new_dir
> find -name *.xml | xargs mv {} new_dir

これにより、現在のディレクトリとサブディレクトリ内のすべてのファイルが new_dir ディレクトリに移動されます。実際には次のように分類されます。

> find -name *.xml | xargs echo mv {} new_dir
> mv foo.xml new_dir
> mv bar.xml new_dir
> mv baz.xml new_dir

xargsそのため、どのように機能するかを考慮parallelして、コマンドで問題を確認できることを願っています。find . -name '*.xml'プログラムに渡される xml ファイルのリストを生成しますscript.sh

> find . -name '*.xml' | parallel -j2 echo script.sh {}
> script.sh foo.xml
> script.sh bar.xml
> script.sh baz.xml

ただし、ls | parallel -j2 script.sh {}現在のディレクトリ内のすべてのファイルのリストを生成して、script.sh プログラムに渡します。

> ls | parallel -j2 echo script.sh {}
> script.sh some_directory
> script.sh some_file
> script.sh foo.xml
> ...

バージョンのより正しいバリアントはls次のようになります。

> ls *.xml | parallel -j2 script.sh {}

ただし、これと find バージョンの重要な違いは、find はファイルのすべてのサブディレクトリを検索するのに対し、ls は現在のディレクトリのみを検索することです。上記のコマンドの同等のfindバージョンはls次のようになります。

> find -maxdepth 1 -name '*.xml'

これは、現在のディレクトリのみを検索します。

于 2011-09-30T20:22:52.747 に答える
4

動作するので、findGNU Parallel が実行しているコマンド (-v または --dryrun を使用) を確認してから、失敗したコマンドを手動で実行してみてください。

ls *.xml | parallel --dryrun -j2 script.sh
find -maxdepth 1 -name '*.xml' | parallel --dryrun -j2 script.sh
于 2011-10-02T15:13:04.000 に答える
3

私は使用していませんが、 &parallelの間に違いがあります。はすべてのファイルとディレクトリを一覧表示しますが、 as は.xmlで終わるファイル (およびディレクトリ) のみを一覧表示します。 Paul Rubel が提案したように、これを確認するには、スクリプトで $1 の値を出力するだけです。さらに、オプションを使用してファイルのみへの入力をフィルタリングすることを検討することもできます。 お役に立てれば!lsfind . -name '*.xml'lsfind . -name '*.xml'
find-type f

于 2011-09-30T13:49:41.323 に答える
2

きちんとした。

私はこれまでパラレルを使用したことがありませんでした。2つあるように見えますが。1 つは Gnu Parallel で、私のシステムにインストールされたものは、man ページの著者として Tollef Fog Heen がリストされています。

ポールが述べたように、 set -x を使用する必要があります

また、あなたが上で述べたパラダイムは私のパラレルではうまくいかないようです。むしろ、私は次のことをしなければなりません:

$ cat ../script.sh
+ cat ../script.sh
#!/bin/bash
echo $@
$ parallel -ij2 ../script.sh {} -- $(find -name '*.xml')
++ find -name '*.xml'
+ parallel -ij2 ../script.sh '{}' -- ./b.xml ./c.xml ./a.xml ./d.xml ./e.xml
./c.xml
./b.xml
./d.xml
./a.xml
./e.xml
$ parallel -ij2 ../script.sh {} -- $(ls *.xml)
++ ls --color=auto a.xml b.xml c.xml d.xml e.xml
+ parallel -ij2 ../script.sh '{}' -- a.xml b.xml c.xml d.xml e.xml
b.xml
a.xml
d.xml
c.xml
e.xml

find は別の入力を提供します。名前の前に相対パスを追加します。多分それがあなたのスクリプトを台無しにしているのですか?

于 2011-09-30T13:59:30.840 に答える