简体   繁体   English

路径名中的空格给Bash中的Find带来麻烦。 任何*简单*解决方案?

[英]Spaces in path names giving trouble with Find in Bash. Any *simple* work-around?

Is there any way to change the following string so I don't get any problems when there are files/folders with spaces in them? 有没有办法更改以下字符串,所以当存在空格的文件/文件夹时,我不会遇到任何问题?

files=`find ~/$folder -name "*@*" -type f`

I'd prefer if there was a solution that wouldn't have to involve having to change other parts of my code but this line of code, as everything seems to be working correctly, apart from this minor detail. 我更喜欢是否有一个解决方案,不必涉及必须更改我的代码的其他部分,但这一行代码,因为一切似乎工作正常,除了这个小细节。

Thanks 谢谢

EDIT: Here is the code in a bit more detail: 编辑:这是更详细的代码:

abc=( $(find "$pasta" -name "$ficheiro_original@*" -type f) )
abc_length=${#abc[@]}

If you are not using those file names later in your script , just iterate them and process on the fly. 如果您稍后在脚本中没有使用这些文件名,只需迭代它们并即时处理。

find ~/$folder -name "*@*" -type f | while read -r FILE
do
  echo "do you stuff"
done

otherwise, you can set IFS 否则,你可以设置IFS

IFS=$'\n'
files=$(find ~/$folder -name "*@*" -type f)

Update: 更新:

$ IFS=$'\n'
$ a=($(find . -type f ))
$ echo ${#a[@]}
14

If you need a list of files that might have spaces in the names, you pretty much have to store them as an array, rather than just a string. 如果您需要名称中可能包含空格的文件列表,则几乎必须将它们存储为数组,而不仅仅是字符串。 Create the array with something like this: 使用以下内容创建数组:

saveIFS="$IFS"; IFS=$'\n'; files=( $(find ~/"$folder" -name "*@*" -type f) ); IFS="$saveIFS"

and then you'll have to modify the rest of the script to use files as an array rather than a string, and it (and other filenames) should always be in double-quotes to keep spaces from being mistaken as separators. 然后你将不得不修改脚本的其余部分以将文件用作数组而不是字符串,并且它(和其他文件名)应始终使用双引号以防止空格被误认为是分隔符。 For instance, anyplace you're currently using $files , replace that with "${files[@]}" 例如,您当前正在使用$files任何地方,请将其替换为"${files[@]}"

ls "${files[@]}"
for f in "${files[@]}"; do
    ls "$f"
done
echo "found ${#files[@]} files" 

You'd have to make some changes, but to deal with arbitrary names, think in terms of using the GNU Find option -print0 , etc. 您必须进行一些更改,但要处理任意名称,请考虑使用GNU Find选项-print0等。

 find ~/$folder -name "*@*" -type f -print0 | while read -d '^@' file do echo "<<$file>>" done 

(Where the single byte represented as ' ^@ ' is actually an ASCII NUL ('\\0'; enter with Control-V Control-Shift-@ ). (表示为' ^@ '的单字节实际上是ASCII NUL('\\ 0';用Control-V Control-Shift- @输入 )。

find ~/$folder -name "*@*" -type f -print0 |
while read -d '' file
do
    echo "<<$file>>"
done

The empty string for the delimiter means 'use the zero byte, ASCII NUL, as the delimiter' and is appropriate for parsing ' find ... -print0 ' output. 分隔符的空字符串表示'使用零字节,ASCII NUL作为分隔符',适用于解析' find ... -print0 '输出。 (Thanks Dennis Williamson for the tip.) (感谢Dennis Williamson的提示。)

This allows you to read any arbitrary names. 这允许您读取任意名称。 You should probably use a bash array to hold the names, but that implies some changes further down the script. 您应该使用bash数组来保存名称,但这意味着脚本中的某些更改。

(Given the comment response that only spaces have to be worried about, this might be overkill, though using read to process lines with the names is a key part of the operation, and using an array would probably make life simpler.) (鉴于只有空格必须担心的注释响应,这可能是过度的,尽管使用read来处理具有名称的行是操作的关键部分,并且使用数组可能会使生活更简单。)

Here is another way to get around without changing the rest of code: 这是另一种不改变其余代码的方法:

# files=($(find))
eval "files=($(find -printf '"%h/%f" '))"

for f in "${files[@]}"; do
  echo "$f"
done

It's dirty and will not work for filename with special characters, eg " . It uses eval to evaluate a string of a Bash array and -printf of find to form that string. 它很脏,对于带有特殊字符的文件名不起作用,例如" 。它使用eval来评估Bash数组的字符串和-printffind来形成该字符串。

I personally prefer changing $IFS , just FYI. 我个人更喜欢改变$IFS ,仅限FYI。

To read file names with spaces into a Bash array variable, you could use the "read" builtin command as well: 要将包含空格的文件名读入Bash数组变量,您还可以使用“read”内置命令:

printf '%q\n' "$IFS"

IFS=$'\n' read -r -d "" -a abc <<< "$(find ~/$folder -name "*@*" -type f)"
IFS=$'\n' read -r -d "" -a abc < <(find ~/$folder -name "*@*" -type f)  # alternative

abc_length=${#abc[@]}

for ((i=1; i <= ${#abc[@]}; i++)); do echo "$i:  ${abc[i-1]}"; done

printf '%q\n' "$IFS"

Note that the scope of the newly set IFS variable is limited to the execution of the read command (which leaves the original IFS variable intact). 请注意,新设置的IFS变量的范围仅限于执行read命令(使原始IFS变量保持原样)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM