基本上我正在使用find命令搜索存在于许多目录中的多字文件,并将输出存储到变量vari
vari = `find -name "multi word file.xml"
当我尝试使用for循环删除文件以迭代时,
for file in ${vari[@]}
执行失败说。,
rm: cannot remove `/abc/xyz/multi':: No such file or directory
你们可以帮助我解决这个问题吗?
答案 0 :(得分:4)
bash
,主要是由于使用了数组而process substitution (<(...)
) [1] ;一个POSIX符合条件的解决方案会更麻烦 [2] ;另请注意,这是一个基于 line 的解决方案,因此它不会处理 embedded 的文件名 newlines正确,但这在实践中非常罕见):# Read matches into array `vari` - safely: no word splitting, no
# globbing. The only caveat is that filenames with *embedded* newlines
# won't be handled correctly, but that's rarely a concern.
# bash 4+:
readarray -t vari < <(find . -name "multi word file.xml")
# bash 3:
IFS=$'\n' read -r -d '' -a vari < <(find . -name "multi word file.xml")
# Invoke `rm` with all array elements:
rm "${vari[@]}" # !! The double quotes are crucial.
find
直接执行删除(这些解决方案还可以正确处理带有嵌入换行符的文件名):find . -name "multi word file.xml" -delete
# If your `find` implementation doesn't support `-delete`:
find . -name "multi word file.xml" -exec rm {} +
至于你的尝试:
vari=`find -name "multi word file.xml"`
(我删除了=
周围的空格,这会导致语法错误)不创建数组;这样的command substitution将封闭命令的stdout输出作为单字符串返回(删除尾随换行符)。
( ... )
中附上命令替换,可以创建一个数组:vari=( `find -name "multi word file.xml"` )
,find
的输出上执行word splitting,而不能正确保留带空格的文件名。IFS=$'\n'
解决此问题,以便仅在行边界处进行分割,但生成的令牌仍然会受pathname expansion (globbing)的影响,这可能会无意中更改文件路径。readarray
或read
是更简单的选择。即使您确实设法在$vari
中正确收集文件路径作为数组,引用该数组为${vari[@]}
- ,但没有双引号 - 会中断,因为生成的字符串再次受 word splitting 和路径名扩展(globbing)的影响。
"${vari[@]}"
[1]
使用进程替换而不是管道,以确保在当前 shell而不是子shell中执行readarray
/ read
正如eckes在评论中指出的那样,如果您尝试使用find ... | IFS=$'\n' read ...
,read
将在子shell 中运行,这意味着变量当命令返回时,它创建将消失(超出范围),以后不能使用。
[2]
POSIX shell规范。既不支持数组也不支持进程替换(readarray
,也不支持read
以外的任何-r
选项;你必须按如下方式实施逐行处理:
while IFS='
' read -r vari; do
pv vari
done <<EOF
$(find . -name "multi word file.xml")
EOF
请注意IFS='
和'
之间的实际换行符,以便在$'\n'
syntax不可用的情况下指定换行符。
答案 1 :(得分:2)
以下是一些方法:
# change the input field separator to a newline to ignore spaces
IFS=$'\n'
for file in $(find . -name '* *.xml'); do
ls "$file"
done
# pipe find result lines to a while loop
IFS=
find . -name '* *.xml' | while read -r file; do
ls "$file"
done
# feed the while loop with process substitution
IFS=
while read -r file; do
ls "$file"
done < <(find . -name '* *.xml')
如果您对结果感到满意,请将ls
替换为rm
。
答案 2 :(得分:0)
解决方案都是基于行的解决方案。底部有一个测试环境,没有已知的解决方案。
如前所述,可以使用此测试命令删除该文件:
$ find . -name "multi word file".xml -exec rm {} +
当路径或文件名包含 \ n 时,我无法使用带有变量的 rm 命令。
测试环境:
$ mkdir "$(printf "\1\2\3\4\5\6\7\10\11\12\13\14\15\16\17\20\21\22\23\24\25\26\27\30\31\32\33\34\35\36\37\40\41\42\43\44\45\46\47testdir" "")"
$ touch "multi word file".xml
$ mv *xml *testdir/
$ touch "2nd multi word file".xml ; mv *xml *testdir
$ ls -b
\001\002\003\004\005\006\a\b\t\n\v\f\r\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037\ !"#$%&'testdir
$ ls -b *testdir
2nd\ multi\ word\ file.xml multi\ word\ file.xml