regex - 重命名多个文件,按 '_' 拆分文件名并保留第一个和最后一个字段

标签 regex awk split rename file-rename

假设我有以下文件:

a_b.txt               a_b_c.txt             a_b_c_d_e.txt         a_b_c_d_e_f_g_h_i.txt
我想以这样的方式重命名它们,我将它们的文件名拆分为 _我保留了第一个和最后一个字段,所以我最终得到:
a_b.txt               a_c.txt             a_e.txt         a_i.txt
以为这很容易,但我有点卡住了......
我试过 rename使用以下正则表达式:
rename 's/^([^_]*).*([^_]*[.]txt)/$1_$2/' *.txt
但我真正需要做的是实际拆分文件名,所以我想到了 awk ,但我对它并不那么精通......这是我目前所拥有的(我知道在某些时候我应该指定 FS="_" 并以某种方式获取第一个和最后一个字段......
find . -name "*.txt" | awk -v mvcmd='mv "%s" "%s"\n' '{old=$0; <<split by _ here somehow and retain first and last fields>>; printf mvcmd,old,$0}'
有什么帮助吗?我没有首选的方法,但是用它来学习会很好awk .谢谢!

最佳答案

您的 rename尝试接近;你只需要确保最后一组是贪婪的。

rename 's/^([^_]*).*_([^_]*[.]txt)$/$1_$2/' *_*_*.txt
我加了一个 _在最后一个左括号之前(这是关键的修复),还有一个 $最后 anchor ,并且还扩展了通配符,这样您就不会处理任何不包含至少两个下划线的文件。
Awk 中的等价物可能看起来像
find . -name "*_*_*.txt" |
awk -F _ '{ system("mv " $0 " " $1 "_" $(NF)) }'
这有点脆弱,因为 system称呼;如果您的文件名可能包含空格或其他 shell 元字符,您可能需要重新考虑您的方法。您可以添加引号以部分修复该问题,但是如果文件名包含文字引号,则该命令将失败。你也可以解决这个问题,但是这对我来说有点太复杂了。
这是一种不那么脆弱的方法,它应该处理完全任意的文件名,即使是其中包含换行符的文件名:
find . -name "*_*_*.txt" -exec sh -c 'for f; do
    mv "$f" "${f%%_*}_${f##*_}"
  done' _ {} +
find将在每个文件名前提供一个前导路径,所以我们不需要 mv --这里(永远不会有以破折号开头的文件名)。
parameter expansion ${f##pattern}产生变量 f 的值最长的可用匹配 pattern从一开始就剪掉了; ${f%%pattern}做同样的事情,但从字符串的末尾修剪。

关于regex - 重命名多个文件,按 '_' 拆分文件名并保留第一个和最后一个字段,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68982956/

相关文章:

带有 regexec() 的 C++ 正则表达式不匹配

python - 用于从两端删除非 ASCII 字符的正则表达式

sql - 按空格分割字符串

python - 我如何在Python中将这个字符串变成2个数组?

c++ - re2 库加载

python - 如何使用选择器选择html元素的属性?

bash - 在文件中插入行

awk - 有没有办法用 sed 替换所有逗号,除了引号中的逗号

Linux 正则表达式不能与 AWK 一起使用

java - 用冒号分割字符串并在 xml 中以新行显示