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


9

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

head.body.date.txt

至:

head_body_date.txt

Unix中是否有单行语句可以进行重命名?


9
您是否认为这.tar.gz是扩展?另外,欢迎来到U&L!
EKons,2016年

2
您真的是说Unix,而不是Linux吗?哪个Unix?
terdon

1
明显的答案是mv head.body.date.txt head_body_date.txt。如果您还有其他限制或实际示例,请使用这些内容更新您的问题。到目前为止,尚不清楚该问题是否涉及具有该显式名称的文件,所有文件都具有特定格式的单个目录,或者是否要在目录层次结构中搜索特定名称并进行更改。
库萨兰达

Answers:


9

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

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

的参数扩展图案,${f//./_}取代所有.与S _S IN的文件名($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

如果有任意数量的点,有一种通用方法吗?
西普里安·托莫阿格(CiprianTomoiagă),2013年

1
@CiprianTomoiaga做:for f in *.*; do ...; done
heemayl

我可能建议*.*在示例中将图案弄直,因为现在代码看起来只适用于固定数量的点。
ilkkachu

@ilkkachu足够公平,已编辑。
heemayl

非常感谢您的帮助,它对我有用。和一些学习!
SG

4

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(是的,严重过时的机器)。


2

bash

old=head.body.date.txt oldb=${old%.*} olde=${old##*.} ; \
mv -- "$old" "${oldb//./_}.${olde}"

(1)您应该使用mv --来防止以开头的“旧”文件名-。(2)您应$old在引号("$old")中加引号,以防止“旧”文件名包含外壳程序专用的空格或字符(如*?)。(3)在扩展名中包含下划线的某种病理情况下,您的答案失败:head.body.date.t_xt重命名为head_body_date_t.xt
斯科特

@斯科特,谢谢。现在,根据上述所有三个项目对代码进行了调整。
agc

1

使用mvsedrev在一行:

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

如果您想将其txt应用于当前rep中的所有文件,由于mv工作原理,使用glob似乎很棘手,但是您可以单线for循环:

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

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


2
(1)啊!不要做$(ls …); 随便吧for file in *.txt。(2)您应该使用更多引号:mv "$file" "$(…)"
斯科特

谢谢Scott,请注意并进行编辑!我仍然是一个空壳的年轻人,请保持谦逊;)
Valentin B.

事后看来,使用rename其他答案中提出的建议确实听起来更简单……
Valentin B.

-1
 mv head.body.date.txt head_body_date.txt

就像一次处理一个文件一样简单。您无需指定是要在目录中还是在整个目录中以递归方式完成此操作,因此这将是您最方便,快捷的解决方案。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.