文書の内容filelist
:
/some/path/*.txt
/other/path/*.dat
/third/path/example.doc
私はこれらのファイルをリストしたいので、次のようにします。
cat filelist | xargs ls
ただし、これらの範囲を拡張する代わりに、次のような結果が得られます。
ls: cannot access '/some/path/*.txt': No such file or directory ls: cannot access '/other/path/*.dat': No such file or directory /third/path/example.doc
答え1
シェルは球を拡張します。ここでは非常にまれです。 Bourneに似たシェル(zshを除く)では、引用符で囲まれていないコマンドの置き換え時に暗黙の分割+glob演算子を呼び出すと便利です。
IFS='
' # split on newline only
set +o noglob # make sure globbing is not disabled
ls -ld -- $(cat filelist) # split+glob
では、zsh
次の操作を行います。
ls -ld -- ${(f)~"$(<filelist)"}
f
改行文字に分割されたパラメータ拡張フラグはどこにありますか?~
必要パラメータの拡張やコマンドの置き換え時には、デフォルトでワイルドカードは実行されません。
一致するファイルのリストが大きい場合、次の問題が発生する可能性があります。パラメータリストが長すぎます。バグ(ほとんどのシステムでのシステムコールの制限execve()
)、xargs
それ以外の場合は解決することができます。では、zsh
以下を使用できますzargs
。
autoload zargs
zargs --eof= -- ${(f)~"$(<filelist)"} '' ls -ld --
必要に応じて制限を避けるために、リストが分割されて複数回実行されますzargs
。ls
xargs
あるいは、リストを組み込みコマンドに渡すこともできます(したがってシステムexecve()
コールは不要です)。
ファイルリストのみ印刷:
print -rC1 -- ${(f)~"$(<filelist)"}
またはxargs
NULで区切って入力してください。
print -rNC1 -- ${(f)~"$(<filelist)"} |
xargs -r0 ls -ld --
ファイルと一致しない glob がある場合は、zsh
エラーメッセージが表示されます。これらのglobを何も拡張したくない場合は、N
glob修飾子をglobに追加できます(これはnullglob
globごとに有効になります)。
print -rNC1 -- ${(f)^~"$(<filelist)"}(N) |
xargs -r0 ls -ld --
これを追加すると、glob演算子を持たないすべての行がglobに変換されるため、パスで参照されているファイルと存在しないファイルがフィルタリングされます。つまり、Express asを渡してこのオプションを有効にしないと、(N)
glob修飾子は使用できません。 。また、修飾子は任意のコードを実行できるため、ファイルの内容が信頼できるソースから出ることが重要です。filelist
(#q...)
extendedglob
filelist
Glob を含む他の Bourne 様シェルでは、bash
一致しない glob は変更されずに残るので、文字通りls
そのファイルが存在しないと報告できるエラーとして渡されます。
では、bash
このオプション(zshからコピー)を使用しnullglob
て、具体的に一致するglobがない場合を処理できます。
shopt -s nullglob
IFS=$'\n'
set +o noglob
set -- $(<filelist)
(( $# == 0 )) || printf '%s\0' "$@" | xargs -r0 ls -ld --
bash
zsh
、glob修飾子と同等のものはありません。 glob演算子のない行(yoursなど/third/path/example.doc
)がglobとして扱われ、実際のファイルと一致しない場合に削除するようにするには、@()
これらの行に追加できます(必須extglob
)。ただし、これは文字で終わる行では機能しません/
。ただし、@()
最後の非文字に追加し、常に存在するという/
事実に頼ることができます。/
shopt -s nullglob extglob
IFS=$'\n'
set +o noglob
set -- $(LC_ALL=C sed 's|.*[^/]|&@()|' filelist)
(( $# == 0 )) || printf '%s\0' "$@" | xargs -r0 ls -ld --
それにもかかわらず、サポートされるglob演算子のリストはシェルによって大きく異なります。しかし、あなたの例()で使用されている唯一のものは*
誰でもサポートする必要があります。
答え2
スクリプトを少し変更し、sh
次から呼び出すことができますxargs
。
cat filelist | xargs -i -- /bin/sh -c 'ls $1' _X_ {}
xargs
それともファイル自体を読んでみましょう。
xargs -a filelist -i -- /bin/sh -c 'ls $1' _X_ {}
答え3
while read filepattern
do
ls $filepattern
done < filelist
この場合、ファイルグロービングを介して変数値を拡張したいので、引用符なしで変数を使用する必要があります。
/some/path/*.txt
シェルは一致するファイルのリストに置き換えられます。
不要なファイル名のみをリストしたい場合ls
。echo
次のものを使用できますecho $filepattern
。
上記のコードとは異なり、引用符を使用すると、質問の例と同じエラーが発生します。なぜなら、シェルは/some/path/*.txt
to のように変更されていない文字列を渡すからですls
。
while read filepattern
do
ls "$filepattern"
done < filelist