空白を含むファイル名を操作するために配列を使用することを提案するBashスクリプトガイドを見てきました。 DashAsBinSh ただし、配列は移植できないことを示唆しているため、空白を含む可能性のあるファイル名のリストを扱うPOSIX準拠の方法を探しています。
以下のスクリプト例を変更して、echo
になるようにしています。
foo/target/a.jar
foo/target/b.jar
bar/target/lol whitespace.jar
これがスクリプトです
#!/usr/bin/env sh
INPUT="foo/target/a.jar
foo/target/b.jar
bar/target/b.jar
bar/target/lol whitespace.jar"
# this would be produced by a 'ls' command
# We can execute the ls within the script, if it helps
dostuffwith() { echo $1; };
F_LOCATIONS=$INPUT
ALL_FILES=$(for f in $F_LOCATIONS; do echo `basename $f`; done)
ALL_FILES=$(echo "$ALL_FILES" | sort | uniq)
for f in $ALL_FILES
do
fpath=$(echo "$F_LOCATIONS" | grep -m1 $f)
dostuffwith $fpath
done
POSIXシェルには1つの配列があります:位置パラメータ($1
、$2
など。まとめて"$@"
と呼ばれます)。
set -- 'foo/target/a.jar' 'foo/target/b.jar' 'bar/target/b.jar' 'bar/target/lol whitespace.jar'
set -- "$@" '/another/one at the end.jar'
…
for jar do
dostuffwith "$jar"
done
これは1つしか存在しないので不便であり、位置パラメータのその他の使用はすべて破棄されます。位置パラメータは関数に対してローカルです。これは、時には祝福であり、時には呪いです。
ファイル名に改行が含まれないことが保証されている場合は、改行を区切り文字として使用できます。変数を展開するときは、最初にset -f
でグロビングをオフにし、フィールド分割文字IFS
のリストに改行のみが含まれるように設定します。
INPUT="foo/target/a.jar
foo/target/b.jar
bar/target/b.jar
bar/target/lol whitespace.jar"
…
set -f; IFS='
' # turn off variable value expansion except for splitting at newlines
for jar in $INPUT; do
set +f; unset IFS
dostuffwith "$jar" # restore globbing and field splitting at all whitespace
done
set +f; unset IFS # do it again in case $INPUT was empty
リスト内の項目が改行で区切られているため、多くのテキスト処理コマンド、特にsort
を便利に使用できます。
明示的にフィールド分割を実行したい場合(およびオフにしていない限りグロブも)を除き、常に変数の引用符を二重引用符で囲むことを忘れないでください。
$INPUT
変数は改行を区切り文字として使用するため、ファイルの名前に改行が含まれないと想定します。そのため、はい、ファイルを反復して空白を保持する簡単な方法があります。
ビルトインread
シェルを使用するのが目的です。通常、read
はすべての空白で分割されるため、空白で分割されます。ただし、IFS=$'\n'
を設定すると、代わりに改行のみで分割されます。したがって、リストの各行を反復処理できます。
これが私が思いつくことができる最小のソリューションです:
INPUT="foo/target/a.jar
foo/target/b.jar
bar/target/b.jar
bar/target/lol whitespace.jar"
dostuffwith() {
echo "$1"
}
echo "$INPUT" | awk -F/ '{if (!seen[$NF]++) print }' | \
while IFS=$'\n' read file; do
dostuffwith "$file"
done
基本的には、「$ INPUT」をawk
に送信します。これは、ファイル名に基づいて重複排除します(/
で分割され、最後の項目が以前に表示されていない場合は行を出力します)。次に、awkがファイルパスのリストを生成したら、while read
を使用してリストを反復処理します。