问题如何重命名文件夹中名称以“_backup”结尾的所有文件@Radu R?deanu 给出了一个对我也有用的好答案:
find . -type f -name '*.jpg_backup' -print0 \
| while IFS= read -r -d '' file ; do mv -- "$file" \
"$(echo $file | sed 's/_backup//g')"; done
Run Code Online (Sandbox Code Playgroud)
不过,我想充分了解他的单行本。确切地说,我不明白的部分是:
while IFS= read -r -d '' file
Run Code Online (Sandbox Code Playgroud)
我知道 IFS 是“内部字段分隔符”,我想这是删除或忽略空格,但我不明白语法和选项。
我也想了解为什么--在 mv 之后是必要的。
有人可以帮忙吗?谢谢。
read word1 word2 … rest 执行以下操作:
IFS变量值中的任何字符都被视为单词分隔符。word,将第二个词分配给变量word2,依此类推。rest,并保留内部的原始单词分隔符。该选项会-r停用第 2 步,因此\行尾的 a 不被视为单词分隔符。
随着IFS设置为空字符串,没有单词分隔,使整条生产线是一个大词:第3步什么也不做,和第5步结束了分配原线至指定的变量。关于为什么IFS设置在这个位置,请参阅为什么while IFS= read这么经常使用,而不是IFS=; while read..?.
该选项-d改变了行的概念:通常一行以换行符结束;使用-d ''(到 的空参数-d),bash 读取由空字节分隔的输入记录。
结果是find … -print0 | while IFS= read -r -d '' file; do …为每个find打印的匹配项执行循环体,而不管文件名中可能出现的任何特殊字符。
至于--in mv -- "$file",它在那里,以防值file以破折号开头:mv将其解释为一个选项。在这种特殊情况下,没有必要,因为此find命令的输出始终以./. --在脚本中系统地使用可以说是良好的卫生习惯。
这个片段有一个缺陷:它仍然无法处理包含空格或\[?*, 因为"$(echo $file | sed 's/_backup//g')"位的文件名。像$file这样的变量扩展不只是替换变量的值:它使用IFS(就像read)的值将变量拆分为单词,并将每个单词视为通配符模式,如果匹配文件列表替换它匹配任何。为避免这种行为,请编写"$file". 这是一个通用的 shell 编程规则:始终在变量替换(以及命令替换$(…))周围加上双引号,除非您知道为什么需要将它们排除在外。(如果你想要细节,请参阅何时需要双引号? ; $VAR vs ${VAR} 并引用或不引用和环境变量中单引号和双引号的意义是什么?也可能有兴趣)。
快速修复是添加双引号:
mv -- "$file" "$(echo "$file" | sed 's/_backup//g')"
Run Code Online (Sandbox Code Playgroud)
由于输入的产生方式,这恰好在这里起作用,但对于file它的一般值在少数情况下失败:
file由字符-后跟其中的一个或多个字母组成Een,echo则将其视为一个选项,不输出任何内容。$file以一个或多个换行符结尾,它们将被截断。Bash 有一个字符串替换,可以在这里代替 sed 使用。它更健壮(您无需担心特殊字符的微妙之处)且速度更快。
mv -- "$file" "${file//_backup/}"
Run Code Online (Sandbox Code Playgroud)
尽管考虑到问题的要求,但这是错误的操作:它删除_backup了文件名中的任何位置,而不是仅在末尾。在这里做对了会更容易。
mv -- "$file" "${file%_backup}"
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2332 次 |
| 最近记录: |