当前位置: 首页>>技术教程>>正文


bash – 空格中断循环的文件名,find命令

, ,

问题描述

我有一个脚本,可以搜索多个子文件夹中的所有文件并将其归档到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。

我尝试将read与while循环配合使用,

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

最佳方案

在这里将forfind一起使用是错误的方法,例如,关于要打开的蠕虫罐,请参见this writeup

推荐的方法是使用here所述的findwhileread。下面是一个适合您的示例:

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

这样,您可以使用空字符(\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 '<pattern>' | 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-compliant的所有文件名-请参阅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.

参考资料

本文由Ubuntu问答整理, 博文地址: https://ubuntuqa.com/article/8717.html,未经允许,请勿转载。