パイプライン内の可変範囲?

パイプライン内の可変範囲?

これは非常にマイナーで近い答えをたくさん見つけましたが、それでも理解できません。デフォルトでは、次のパラメータを使用してスクリプトを作成しました。

var1=$1
echo "outside the pipe, my variable is set: $var1"
ls *.* | xargs sh -c 'echo "$0" "$@"; echo "inside the pipe, my variable is empty: $var1"'

私の問題は、私の変数の1つでファイル名のリストをパイプする必要があることです。どうすればいいですか?ファイルのリストを配列に書き込み、パラメータを追加/前に追加してパイプに渡そうとしましたが、後でチャンクとして処理すると問題が発生します。元のスクリプトは次のとおりです(imagemagick)。

ls *.png | xargs -n 100 sh -c 'convert "$0" "$@" -evaluate-sequence $var1 ../out2/"$0"'

どんな助けでも大変感謝します!

答え1

いいえ、ファイル名のリストをパイプする必要はありません。

var1=$1

find . -maxdepth 1 -type f -name '*.png' -exec sh -c '
    var1=$1; first=$2; shift 2
    convert "$first" "$@" -evaluate-sequence "$var1" ../out2/"$first"' sh "$var1" {} +

つまり、内部サブシェルを$var1最初の引数として使用します(0番目の引数はシェルの名前でなければなりません)。

$var1内部シェルは引数のリストを削除し、見つかったfind最初のパス名に対して同じことを行います(理由はわかりませんが、少なくともコードが実行していると思うのと同じにします)。それ$@からshift 2

100単位でこれを行う必要がある場合:

var1=$1

find . -maxdepth 1 -type f -name '*.png' -print0 |
xargs -0 -n 100 sh -c '
    var1=$1; first=$2; shift 2
    convert "$first" "$@" -evaluate-sequence "$var1" ../out2/"$first"' sh "$var1"

これがパイプ出力よりも安全な理由は、パスls名が改行で終わるリストではなくヌルで終わるリストに渡されるためです。スクリプトshは両方のバリエーションと同じで、$var1コマンドライン引数として提供されます。

コードが機能しない理由は、シェルが親シェルで何が起こっているのかsh -cわからないからです。$var1

関連:

答え2

実際、これを行うために他のシェルを実行する必要はありません。 glob式に一致するすべてのファイルを処理するには、最終的に実行したいプログラムのコマンドラインでglobを使用します。

convert *.png -whatever /some/output/path

ファイルの一部にのみアクセスする必要がある場合は、そのファイルを配列に保存し、スライスまたはインデックス付けします。

files=(*.png)
convert "${files[0]}" "${files[@]:1}" -evaluate-sequence "$var1" ../out2/"${files[0]}"

"${files[0]}"最初のファイル名で、"${files[@]:1}"他のすべてのファイルに展開されます)

これにより、一度に100個のファイルを処理できます。

for (( i=0; i < "${#files[@]}" ; i+=100 )); do 
    convert "${files[@]:i:100}" -evaluate-sequence "$var1" ../out2/"${files[i]}"
done

つまり、私があなたの命令を正しく解釈したらxargs。最初のファイル名を0番目の引数sh -c(通常はシェル名)に渡すようです。


ただし、質問に答えるには、export変数を使用して内部シェルに表示するか、二重引用符で囲んでシェルで拡張することができます。例えば

var=foo
export var
echo bar | xargs sh -c 'echo "$var" "$1"' sh

または

var=foo
echo bar | xargs sh -c "echo '$var' "'"$1"' sh

両方とも出力されますfoo bar。環境を渡すと、構文がよりきれいになり(周囲$var$1後者のさまざまなタイプの引用符を参照)、変数の値の引用符が2番目の場合のように問題を引き起こさないため、より良いです。

答え3

これはsh -c新しいシェルなので、子プロセスがそれを所有するか引数として渡すようにexportofを実行する必要があります。$var1sh -c

例の別の問題は、単一のティック内に変数があることです。

関連情報