带有空格的 Bash 变量(目录)

带有空格的 Bash 变量(目录)

我试图回显所有文件,/foo同时保留列出的目录中的空格。目前,标题为 的目录"bar1 bar2"将回显为/path/to/foo/bar1/然后/bar2然后file.txt全部在新行上。我需要它回显/path/to/foo/bar1 bar2/file.txt/path/to/foo/bar1\ bar2/file.txt

for file in $(find /path/to/foo/ -type f); do
  if [[ ... ]]; then
    echo "${file}"
  fi
done

还尝试过:

for file in $(find /path/to/foo/ -type f | sed 's/ /\ /g'); do
  if [[ ... ]]; then
    echo "${file}"
    echo "$file" # variations i've tried
    echo $file   # variations i've tried
    echo ${file}
    otherCommand "${file}"
  fi
done

答案1

问题不在于$file,而在于您对 的使用$(find…)

常规变量和$(…)进程替换都遵循完全相同的分词规则。如果你使用$(find…)双引号,则会得到单身的单词全部输出。如果不这样做,它将在任何空格处拆分 –不是只是换行符或者其他一些你可能预料到的神奇边界。

上述内容的一个重要部分是反斜杠转义符不是扩展变量时进行处理。它只是在空格处进行拆分,仅此而已。

(换句话说,引用$file没有帮助,因为它从一开始就没有正确的值!)

如果您想递归处理所有文件,您的选择是:

  1. find以另一种方式读取输出:

    find … -print | while read -r file; do
        echo "Got $file"
    done
    

    (附注:文件名可能技术上也包括换行符,因此您可能需要防范这种情况,尽管这种情况很少见:

    find … -print0 | while read -r -d "" file; do
        echo "Got $file"
    done
    
  2. 对于少量文件,使用 bash 的扩展通配符:

    shopt -s globstar
    for file in /path/to/foo/**; do
        echo "Got $file"
    done
    

对于大型目录, 的优势find | while read在于它是流式传输的 – 您的脚本将在结果出现时进行处理。同时,$(find)和 通配符都必须收集一切存入内存,然后才返回(可能大量的)结果。

另一方面,使用管道会影响全部的 while循环(而不仅仅是命令read),所以如果你想运行任何事物想要读取键盘输入,您必须手动为其提供原始标准输入,例如vim "$file" < /dev/tty

相关内容