Bow*_*ark 3 shell bash ubuntu sed files
我想重命名一系列以这种方式命名的文件
name (10).ext
name (11).ext
...
Run Code Online (Sandbox Code Playgroud)
到
name_10.ext
name_11.ext
...
Run Code Online (Sandbox Code Playgroud)
这个单行作品:
$ for i in name\ \(* ; do echo "$i" | sed -e 's! (\([0-9]\{2\}\))!_\1!' ; done
name_10.ext
name_11.ext
...
Run Code Online (Sandbox Code Playgroud)
但这个没有:
$ for i in name\ \(* ; do mv "$i" "$(echo "$i" | sed -e 's! (\([0-9]\{2\}\))!_\1!')" ; done
bash: !_\1!': event not found
Run Code Online (Sandbox Code Playgroud)
为什么?如何避免这种情况?
使用
$ bash --version
GNU bash, versione 4.3.48(1)-release (x86_64-pc-linux-gnu)
Run Code Online (Sandbox Code Playgroud)
在 Ubuntu 18.04 上。
虽然在这个类似的问题中显示了一个简单的情况!,但这里!只考虑了!内部单引号,并将其与内部单引号、内部双引号进行比较。正如评论中所指出的,Bash 在这两种情况下的行为方式不同。这是关于 Bash 版本的4.3.48(1);这个问题似乎不再存在4.4.12(1)(但是建议避免这种单行,因为在某些情况下 Bash 版本可能是未知的)。
正如 Kusalananda 的回答中所建议的,如果sed分隔符!被替换为#,
$ for i in name\ \(* ; do mv "$i" "$(echo "$i" | sed -e 's# (\([0-9]\{2\}\))#_\1#')" ; done
Run Code Online (Sandbox Code Playgroud)
这个问题根本不会出现。
在交互式 shell 中使用时,!可能会启动历史扩展(不是脚本中的问题)。
解决方案是!在sed表达式中使用另一个分隔符。
一个替代bash循环:
for name in "name ("*").ext"; do
if [[ "$name" =~ (.*)" ("([^\)]+)").ext" ]]; then
newname="${BASH_REMATCH[1]}_${BASH_REMATCH[2]}.ext"
printf 'Would move %s to %s\n' "$name" "$newname"
# mv -i "$name" "$newname"
fi
done
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
500 次 |
| 最近记录: |