处理“mv”的变量空间

处理“mv”的变量空间

假设我有一个包含以下文件/目录的目录:

google
apple
mozilla foundation   # a file with spaces
browsers

所以我想将文件移动到browsers目录中。这是我写的一个脚本:

for d in $(ls); do
    if ! [ "$d" == "browsers" ]; then
        mv "$d" "browsers"
    fi
done

然后googleapple了,browsers但我得到了:

mv: cannot stat 'mozilla': No such file or directory
mv: cannot stat 'foundation': No such file or directory

显然,问题出在变量中的空格。处理这个问题的正确方法是什么?

当然,我相信应该有一个更优雅的单行命令来执行此操作,但我想知道应该如何使用带有空格的变量。

答案1

不是曾经使用过:

for d in $(ls)

使用这个代替:

for d in *

使用 时存在的两个问题$(ls)是 shell 将 的结果服从$(ls)分词路径名扩展。就你而言,它是分词这导致 mozilla foundation变成mozillafoundation

有关不使用原因的详细讨论$(ls),请参阅“做什么$(ls *.txt)?”

如果您需要考虑目录中没有非隐藏文件的情况(这种情况可能看起来更好,因为它不会在循环中执行任何传递,for i in $(ls)而不是在循环中执行一次传递(*除了在)) 中,您希望告诉 shell 不要扩展到任何不匹配的 glob:$ifor i in *zsh

  • zsh:for i in *(N)
  • ksh93:for i in ~(N)*
  • bash4.4+: f() { local -; shopt -s nullglob; for i in *; ...; done; }; f(重点是nullglob在本地使用该选项(另请参阅该选项以了解与默认选项failglob类似的行为))。zsh
  • yash:(然后重置,据我所知,set -o nullglob没有本地范围的选项)yash
  • 在其他 shell 中,您始终可以[ -e "$i" ] || [ -L "$i" ] || continue在循环中添加 a 来检查文件是否存在。

答案2

不解析ls结果,除了 John1024 的答案之外,您还可以使用find.

LC_ALL=C find . ! -name . -prune ! -name '.*' -type f -exec mv -t /path/to/dest {} +

(这里假设使用 GNUfind选项-t,跳过隐藏文件,如ls*glob 并排除非常规文件。请注意,该列表未排序(与ls或相反*)。LC_ALL=C需要正确跳过名称以.这些开头的任何文件不包含用户区域设置中的有效字符,但这会影响错误消息的语言)。

相关内容