bashがファイル名を正しく読み取れるように、grepの出力をどのようにエスケープしますか?
findコマンドの出力であるテキストファイルがあります。各行ごとにシンボリックリンクを作成したいと思います。今はループをテストしていますls
。ただし、特殊文字については、grepの文字列出力を正しく引用しません。これにより、各ファイルのファイルシステムコマンドが失敗します。
$ tree dir/
dir/
├── Another & file ' name.txt
└── file name.txt
0 directories, 2 files
$ cat files.txt
dir
dir/Another & file ' name.txt
dir/file name.txt
$ grep file files.txt | awk -v q='"' '{printf(q"%s"q"\n", $0);}'
"dir/Another & file ' name.txt"
"dir/file name.txt"
$ while read p ; do
echo $p; ls $(grep file files.txt | awk -v q='"' '{printf(q"%s"q"\n", $0);}') ;
done < files.txt
dir
ls: cannot access '"dir/Another': No such file or directory
ls: cannot access '&': No such file or directory
ls: cannot access 'file': No such file or directory
...
dir/Another & file ' name.txt
ls: cannot access '"dir/Another': No such file or directory
ls: cannot access '&': No such file or directory
ls: cannot access 'file': No such file or directory
...
一重引用符と二重引用符を使用してみました。 grepのパス出力でコマンドを実行するにはどうすればよいですか?
答え1
存在する
ls $(grep file file.txt)
分割+グローブ演算子を誤って使用しており、ここに問題があります。出力がシェルコードとして解釈されないので(ありがとう!)、出力に引用符を挿入したくありませんが、grep
分割+グローブ演算子を調整する必要があります。
ここ
*
glob部分(例:現在のディレクトリのファイルリストに単語を拡張する)は必要ないので、次の方法で無効にする必要があります。set -o noglob
grep
出力を改行文字に分割するだけです(これはファイル名に改行文字を含めることはできませんが、これはfile.txt
ファイル形式の制限です)。IFS=' '
または
IFS=$'\n'
一部の殻では。
その後、引用符なしで分割+glob演算子を呼び出すことができますが、次のように$(...)
なります。
ls -d -- $(grep file files.txt)
Split+glob 演算子は Bourne シェルから継承されたバグです。最新のシェルには、いくつかのテキストを行リストに分割する別の方法があります。
zshを使う:
ls -d -- ${(f)"$(grep file files.txt)"}
パラメータf
拡張フラグは改行(改行)に分割されます。Fps:\n:'
eed)は、その文字列内のエスケープシーケンスを理解するためにs:string:
文字列を分割する略語です。私たちはSplit + glob演算子を無効にすると引用します。p
\n
$(...)
zsh
分ける部分(なし全体的な状況)。
そしてbash
:
readarray -t files < <(grep file files.txt)
ls -d -- "${files[@]}"
xargs
asを使用する入力形式がスペースで区切られたリストである場合は、引用符を挿入できます。xargs
ここで、区切り文字は一重引用符、二重引用符、またはバックスラッシュで囲むことができます(ただし、シェル引用のような方法ではありません)。
だからあなたはこれを行うことができます:
sed '
s/"/"\\""/; # escape the " characters themselves
s/^/"/;s/$/"/; # insert one at the beginning and one at the end
' < files.txt | xargs ls -d --