【问题标题】:What's wrong with this file renaming loop?这个文件重命名循环有什么问题?
【发布时间】:2018-03-11 01:51:18
【问题描述】:

我正在尝试遍历目录中的所有文件,并使用以下命令将它们从前缀 ABC 重命名为 XYZ

while read file; do mv \"$file\" \"$(echo $file | sed -e s/ABC/XYZ/g)\" ; done < <(ls -1)

当我在mv 前面抛出一个回显时,一切看起来都应该可以正常工作,并且复制/粘贴输出的命令也可以正常工作,但它不会在循环上下文中正确执行,给我一个使用错误好像命令格式错误,如下所示。

usage: mv [-f | -i | -n] [-v] source target
       mv [-f | -i | -n] [-v] source ... directory

即使使用 echo 检查输出的命令给出了

mv "ABC Test1" "XYZ Test1"

如果我复制粘贴,这应该是一个有效的命令并且可以工作。

知道发生了什么吗?

【问题讨论】:

  • 我在这里使用while read file; do mv $file $(echo $file | sed -e s/ABC/XYZ/g) ; done &lt; &lt;(ls -1) 进行了测试,它成功了...您收到的信息是什么?
  • 见下文。转义的引号产生了正确的回声输出,但在 mv 中没有预期的功能。删除转义符解决了这个问题。

标签: bash loops redirect pipe


【解决方案1】:

替换:

while read file; do mv \"$file\" \"$(echo $file | sed -e s/ABC/XYZ/g)\" ; done < <(ls -1)

与:

for file in *
do
    mv "$file" "${file//ABC/XYZ}"
done

注意事项:

  1. 这很重要:Never parse ls. ls 仅用于产生人性化的输出。

  2. 要遍历目录中的所有文件,请使用for file in *; do ...; done。这将可靠地适用于所有类型的文件名,包括带有换行符、空格或其他难读字符的文件名。

  3. \" 生成文字字符,而不是句法字符。因为我们想要 " 的语法含义,所以我们不转义。

  4. 有时需要sed,但这不是其中之一。 shell 能够进行简单的替换,而不会出现与命令替换相关的所有问题。因此,$(echo $file | sed -e s/ABC/XYZ/g) 可以替换为${file//ABC/XYZ}

    ${var//old/new} 的形式称为 模式替换,并记录在 man bash 中。

【讨论】:

  • 感谢您的回答。 * 可能比使用 ls -1 更好,但如果 ls -1 被 read 解析,它们是否没有相同的预期效果? ${} 的技术名称是什么?我想读它
  • ls 的输出可能不明确和/或如果您的文件名包含许多特殊字符(在文件名中是完全合法的)中的任何一个,可能会混淆read* 根本没有这个问题。顺便说一句,使用echo 通常是找出将执行什么命令的不好方法,因为它只打印文字引号和转义,而不是语法引号和转义;这可能非常具有误导性(如您所见)。
  • @snowman4839 仅举一个例子,文件名最好包含换行符。因此,循环 ls -1 可能会导致问题。有关更多信息,请参阅this excellent discussion。另外,${var//old/new} 称为 模式替换,并记录在 man bash
【解决方案2】:

非常愚蠢的错误。无需转义 mv 命令中的引号。把它们拿出来让它按预期工作。转义引号会显示带有 echo 的正确输出,但不会给出预期的行为。

while read file; do mv "$file" "$(echo $file | sed -e s/ABC/XYZ/g)" ; done &lt; &lt;(ls -1)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-03-13
    • 2013-09-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多