将文件名中的点替换为下划线(扩展名除外)

将文件名中的点替换为下划线(扩展名除外)

有人可以建议如何重命名文件名:

head.body.date.txt

到:

head_body_date.txt

是否有单行语句来进行重命名Unix

答案1

迭代文件名,并使用参数扩展进行转换:

for f in *.*.*.txt; do i="${f%.txt}"; echo mv -i -- "$f" "${i//./_}.txt"; done

参数扩展模式,将文件名中的${f//./_}所有.s 替换为s ( )。_$f

上面将进行一次空运行,为了进行实际的重命名,请删除echo

for f in *.*.*.txt; do i="${f%.txt}"; mv -i -- "$f" "${i//./_}.txt"; done

如果您想处理任何扩展,而不仅仅是.txt

for f in *.*.*.*; do pre="${f%.*}"; suf="${f##*.}"; \
                     echo mv -i -- "$f" "${pre//./_}.${suf}"; done

检查删除后的echo实际操作:

for f in *.*.*.*; do pre="${f%.*}"; suf="${f##*.}"; \
                     mv -i -- "$f" "${pre//./_}.${suf}"; done

通用,对于任意数量的点,至少有一个:

for f in *.*; do pre="${f%.*}"; suf="${f##*.}"; \
                 mv -i -- "$f" "${pre//./_}.${suf}"; done

答案2

perl基于rename

$ rename -n 's/\.[^.]+$(*SKIP)(*F)|\./_/g' head.body.date.txt 
rename(head.body.date.txt, head_body_date.txt)
  • \.[^.]+$(*SKIP)(*F)跳过此模式并寻找替代匹配
  • |\./_/g全部替换._

或者,使用负前瞻

$ rename -n 's/\.(?![^.]+$)/_/g' head.body.date.txt 
rename(head.body.date.txt, head_body_date.txt)

确定后,删除该-n选项

答案3

rename 's/\.(?=[^.]*\.)/_/g' *.txt

使用正则表达式替换查找.文件名中除最后一个实例之外的所有实例(非捕获先行)并将它们替换为_.*.*如果您愿意的话,可以概括。

(这个特定版本rename似乎是通过安装的util-linux)。我正在使用Ubuntu 12.04(是的,严重过时的机器)。

答案4

使用mv在一行中,sed和:rev

mv "head.body.date.txt" "$(echo head.body.date.txt | rev | sed 's/\./_/2g' | rev)"

如果你想将它应用到所有txt当前代表中的所有文件上,使用 glob 似乎很棘手,因为它的mv工作原理,但你可以for在一行中执行一个循环:

for file in *.txt; do mv "$file" "$(echo $file | rev | sed 's/\./_/2g' | rev)"; done

稍长一些,但您可以在循环中匹配多个模式!

相关内容