shell 脚本中基于查找的 mv 重命名失败

shell 脚本中基于查找的 mv 重命名失败

我想做一个简单的脚本来重命名文件,以及文件的一部分。虽然该命令在命令行中运行得很好:

find . -type f -name "*old*" -exec bash -c 'mv "$0" "${0/old/new}"' {} \; 2>&1 | grep -v "Permission denied" | grep -v "are the same file"

我尝试在 shellscript 中重新实现它:

#!/bin/bash
# renamefiles.sh - type renamefiles <old> <new>
# 
find . -type f -name "*$1*" -exec bash -c 'mv "$0" "${0/$1/$2}"' {} \; 2>&1 | grep -v "Permission denied" | grep -v "are the same file"

当用户输入时,

$ renamefiles old new

将会发生故障(禁用错误消息抑制):

mv: './File0_old.txt' and './File0_new.txt' are the same file
mv: './Another_old_file.txt' and './Another_new_file.txt' are the same file

答案1

让我们首先从两种可能的解决方案开始,然后描述出现错误的原因。

解决方案1::

只需“暂时”导出这两个变量,以便它们可供您的子 shell 使用

#!/bin/bash
# renamefiles.sh - type renamefiles <old> <new>

export from="$1" && export to="$2" && find . -type f -name "*$1*" -exec bash -c 'mv "$0" "${0/$from/$to}"' "{}" \; 2>&1 | grep -v "Permission denied"


exit 0

所以这里我们将 $1 导出到变量 from 中,将 $2 导出到变量 to 中。这样,子 shell 将能够读取它们。

解决方案2::(更简单,可能是那些不喜欢临时导出的人更喜欢的)

#!/bin/bash
# renamefiles.sh - type renamefiles <old> <new>

find . -type f -name "*$1*" -exec bash -c 'mv "$0" "${0/$1/$2}"' "{}" "$1" "$2" \; 2>&1 | grep -v "Permission denied"

exit 0

该解决方案包括在 {}(find 的当前结果)之外仅传递“$1”和“$2”,以便子 shell 可以正常访问它们,就像它自己是一个脚本一样(例外情况是 - c 选项传递给 bash,第一个参数将是 $0 而不是 $1;这似乎是你知道的,因为你已经使用过它)

关于这两种解决方案的常见注意事项:

  1. 始终在脚本末尾包含退出命令
  2. 请注意所传递的每个变量的引号,即使是 {}。这可以防止对带有空格的变量的误解。即使您确定没有带空格的值或[此处]文件名,也请执行此操作,因为您不知道稍后何时会使用脚本。

错误背后的原因::

您收到的错误(“是同一个文件”)背后的原因非常简单。

在您的脚本中,mv 命令将给定文件“$0”替换为字符串替换结果给出的另一个文件(“${0/$1/$2}”)。因此,在您的情况下,$1 和 $2 没有提供给子 shell 命令,所以就像您执行了“${0//}”一样,它什么也不做。结果,新旧文件名将相同,因此会出现错误。

相关内容