带有空格的文件名为循环,查找命令

我有一个脚本,可以搜索多个子文件夹和档案中的所有文件到tar。 我的剧本是

for FILE in `find . -type f -name '*.*'` do if [[ ! -f archive.tar ]]; then tar -cpf archive.tar $FILE else tar -upf archive.tar $FILE fi done 

find命令给出了以下输出

 find . -type f -iname '*.*' ./F1/F1-2013-03-19 160413.csv ./F1/F1-2013-03-19 164411.csv ./F1-FAILED/F2/F1-2013-03-19 154412.csv ./F1-FAILED/F3/F1-2011-10-02 212910.csv ./F1-ARCHIVE/F1-2012-06-30 004408.csv ./F1-ARCHIVE/F1-2012-05-08 190408.csv 

但是FILE变量只存储路径的第一部分./F1/F1-2013-03-19 ,然后存储下一部分160413.csv

我尝试使用带有while循环的read

 while read `find . -type f -iname '*.*'`; do ls $REPLY; done 

但是我收到以下错误

 bash: read: `./F1/F1-2013-03-19': not a valid identifier 

任何人都可以建议另一种方式?

更新

正如下面的答案所示,我更新了脚本

 #!/bin/bash INPUT_DIR=/usr/local/F1 cd $INPUT_DIR for FILE in "$(find . -type f -iname '*.*')" do archive=archive.tar if [ -f $archive ]; then tar uvf $archive "$FILE" else tar -cvf $archive "$FILE" fi done 

我得到的输出是

 ./test.sh tar: ./F1/F1-2013-03-19 160413.csv\n./F1/F1-2013-03-19 164411.csv\n./F1/F1-2013-03-19 153413.csv\n./F1/F1-2013-03-19 154412.csv\n./F1/F1-2012-09-10 113409.csv\n./F1/F1-2013-03-19 152411.csv\n./.tar\n./F1-FAILED/F3/F1-2013-03-19 154412.csv\n./F1-FAILED/F3/F1-2013-03-19 170411.csv\n./F1-FAILED/F3/F1-2012-09-10 113409.csv\n./F1-FAILED/F2/F1-2011-10-03 113911.csv\n./F1-FAILED/F2/F1-2011-10-02 165908.csv\n./F1-FAILED/F2/F1-2011-10-02 212910.csv\n./F1-ARCHIVE/F1-2012-06-30 004408.csv\n./F1-ARCHIVE/F1-2011-08-17 133905.csv\n./F1-ARCHIVE/F1-2012-10-21 154410.csv\n./F1-ARCHIVE/F1-2012-05-08 190408.csv: Cannot stat: No such file or directory tar: Exiting with failure status due to previous errors 

在这里使用for with是一种错误的方法,例如,请参阅这篇关于你正在打开的蠕虫病毒的文章。

推荐的方法是使用findwhileread如此处所述。 以下是一个适合您的示例:

 find . -type f -name '*.*' -print0 | while IFS= read -r -d '' file; do printf '%s\n' "$file" done 

这样,您可以使用null( \0 )字符分隔文件名,这意味着空格和其他特殊字符的变化不会导致问题。

要使用find的文件更新存档,可以将其输出直接传递给tar

 find . -type f -name '*.*' -printf '%p\0' | tar --null -uf archive.tar -T - 

请注意,您不必区分存档是否存在, tar将合理地处理它。 另请注意在此处使用-printf以避免在归档中包含./位。

尝试像这样引用for循环:

 for FILE in "`find . -type f -name '*.*'`" # note the quotation marks 

没有引号,bash根本不处理空格和换行符( \n )……

也尝试设置

 IFS=$'\n' 

这工作并且更简单:

 find . -name '' | while read LINE; do echo "$LINE" ; done 

感谢Rupa( https://github.com/rupa/z )获得此答案。

除了正确引用之外,您还可以告诉find使用NULL分隔符,然后在while循环中读取和处理结果

 while read -rd $'\0' file; do something with "$file" done < <(find . -type f -name '*.*' -print0) 

这应该处理任何符合POSIX标准的文件名 - 请参阅man find

  -print0 True; print the full file name on the standard output, followed by a null character (instead of the newline character that -print uses). This allows file names that contain newlines or other types of white space to be correctly interpreted by programs that process the find output. This option corresponds to the -0 option of xargs. 
 find .  -print0 | xargs -0 grep  

我做了类似这样的事情来查找可能包含空格的文件。

 IFS=$'\n' for FILE in `/usr/bin/find $DST/shared -name *.nsf | grep -v bookmark.nsf | grep -v names.nsf`; do file $FILE | tee -a $LOG done 

像魅力一样工作:)

如果文件名中有换行符,则此处的大多数答案都会中断。 我使用bash超过15年,但只有互动。

在Python中你可以使用os.walk(): http : //docs.python.org/2/library/os.html#os.walk

和tarfile模块: http : //docs.python.org/2/library/tarfile.html#tar-examples

我认为使用find的-exec选项可能会更好。

 find . -type f -name '*.*' -exec tar -cpf archive.tar {} + 

然后查找使用系统调用执行命令,以便保留空格和换行符(而不是管道,这需要引用特殊字符)。 请注意,无论归档是否已存在,“tar -c”都有效,并且(至少使用bash){}和+ +都不需要引用。

正如minerz029建议的那样,你需要引用find命令的扩展。 您还需要在循环中引用$FILE所有替换。

 for FILE in "$(find . -type f -name '*.*')" do if [ ! -f archive.tar ]; then tar -cpf archive.tar "$FILE" else tar -upf archive.tar "$FILE" fi done 

请注意, $()语法应该优先使用反引号; 看到这个U&L问题 。 我还删除了[[关键字并将其替换为[命令,因为它是POSIX。