![shell 脚本中基于查找的 mv 重命名失败](https://linux22.com/image/166461/shell%20%E8%84%9A%E6%9C%AC%E4%B8%AD%E5%9F%BA%E4%BA%8E%E6%9F%A5%E6%89%BE%E7%9A%84%20mv%20%E9%87%8D%E5%91%BD%E5%90%8D%E5%A4%B1%E8%B4%A5.png)
我想做一个简单的脚本来重命名文件,以及文件的一部分。虽然该命令在命令行中运行得很好:
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;这似乎是你知道的,因为你已经使用过它)
关于这两种解决方案的常见注意事项:
- 始终在脚本末尾包含退出命令
- 请注意所传递的每个变量的引号,即使是 {}。这可以防止对带有空格的变量的误解。即使您确定没有带空格的值或[此处]文件名,也请执行此操作,因为您不知道稍后何时会使用脚本。
错误背后的原因::
您收到的错误(“是同一个文件”)背后的原因非常简单。
在您的脚本中,mv 命令将给定文件“$0”替换为字符串替换结果给出的另一个文件(“${0/$1/$2}”)。因此,在您的情况下,$1 和 $2 没有提供给子 shell 命令,所以就像您执行了“${0//}”一样,它什么也不做。结果,新旧文件名将相同,因此会出现错误。