【问题标题】:Bash: var expansion confusion possibly due to IFS [duplicate]Bash:可能由于 IFS [重复]
【发布时间】:2018-01-31 23:46:20
【问题描述】:

在阅读了getting files with spaces in the name using find 之后,我整理了一个小代码块来抓取目录中的所有.sh 文件并使其可执行:

find . -type f -name '*.sh' -print0 | 
while IFS= read -r -d '' file; do
  name=$(printf '%s\n' "$file" | sed "s|^\./||")
  echo $name
  if ! [[ -x $name ]] ; then
    chmod +x "${name}"
  fi
done

倒数第三行给我带来了最大的麻烦。我经历了所有 3 种排列:

chmod +x $name
chmod +x ${name}
chmod +x "${name}"

我有两个问题:

  1. 我想知道为什么最后一个,而且只有最后一个有效。和之前设置的IFS位有关系吗?

  2. 如果有更简单的方法可以做到这一点,它会是什么?同样,它应该抓取当前目录中的所有.sh 文件——所有这些文件的文件名中都有空格——并使其可执行。

【问题讨论】:

  • 您应该始终引用变量,如果它们可以包含空格或全局字符,则更应如此。至于更简单的方法:find . -type f -name '*.sh' -exec chmod +x {} +
  • 还有一点:find -name "*.sh" ! -executable -exec chmod +x {} + 只处理尚未执行的文件。请注意, finds (GNU-find) exec 选项使得对空白的处理变得多余。
  • 我投票重新提出问题,因为 find 提供了选项,这使得对空格的复杂处理变得多余,但 find 不是链接答案的主题。
  • 我们在文件名中有空格,因为它们是由 OS X 机器上的其他系统生成和使用的。 GNU-find / exec 的相同规则是否仍然适用?

标签: bash find whitespace variable-expansion ifs


【解决方案1】:

当您在命令的开头放置变量赋值时,它仅适用于该命令。所以你之前设置的IFS 只被read 命令使用。其余代码使用默认的IFS,其中有空格作为字段分隔符。

如果您希望IFS 设置应用于所有代码,您需要将其作为单独的语句进行,而不是作为命令的前缀。

IFS=
find . -type f -name '*.sh' -print0 | 
while read -r -d '' file; do
  name=$(printf '%s\n' "$file" | sed "s|^\./||")
  echo $name
  if ! [[ -x $name ]] ; then
    chmod +x "${name}"
  fi
done

但通常你应该引用你的变量。即使设置了IFS,如果变量包含通配符也会有问题,因为在扩展未引用的变量后会扩展通配符。仅当您确实需要分词和通配符时才不要引用变量。

【讨论】:

    猜你喜欢
    • 2018-12-05
    • 2015-08-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-24
    • 1970-01-01
    相关资源
    最近更新 更多