带有空格的文件名为循环,查找命令
我有一个脚本,可以搜索多个子文件夹和档案中的所有文件到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是一种错误的方法,例如,请参阅这篇关于你正在打开的蠕虫病毒的文章。
推荐的方法是使用find
, while
和read
如此处所述。 以下是一个适合您的示例:
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。