如何使用sed更改文件扩展名?

6

我需要使用sed命令(还要使用Linux中的管道)更改文件扩展名,以便可以执行类似mv *.txt *.c的操作。问题在于我不能使用batch或for循环,所以我必须全部使用管道和sed命令。


2
为什么你不能使用循环?你应该讲清楚!你是作为作业的一部分吗? - iamauser
当然是的,我没有提到,但我认为这是相当明显的,因为有限制。 - heythatsmekri
7个回答

12

您可以使用字符串操作

filename="file.ext1"
mv "${filename}" "${filename/%ext1/ext2}"
如果您的系统支持,您可以使用rename更新 您还可以尝试像这样做:
mv ${filename}{ext1,ext2}

这被称为花括号展开


我想知道我们是否可以使用 rename 命令...它在大多数 Linux 系统中都可用。 - CS Pei
谢谢,但我不能使用任何批处理或脚本语句,我只能使用我的命令行、sed和管道。 - heythatsmekri
你的输入是什么?你期望什么样的输出?如果只允许使用 sed,我认为你无法重命名文件。 - CS Pei
2
@user2113403:for filename in *.1stextension; do mv "${filename}" "${filename/%1stextension/2ndextension}"; done 这段代码可以用于批量处理文件。不需要使用 sed - bitmask
POSIX: ${filename%.ext1}.ext2 POSIX:${filename%.ext1}.ext2 - OJFord

5

sed用于操作文件内容,而不是文件名本身。我的建议:

rename 's/\.ext/\.newext/' ./*.ext

或者,这里有一个现成的问题,可以帮助您解决: 使用sed批量重命名文件

我不得不在Makefile中将“.c”替换为“.o”。这解决了我的问题,谢谢。 - Garini

4
这可能有效:
find . -name "*.txt" | 
sed -e 's|./||g' | 
awk '{print "mv",$1, $1"c"}' | 
sed -e "s|\.txtc|\.c|g" > table;
chmod u+x table;
./table

我不知道为什么你不能使用循环语句,使用它可以让生活更加轻松:

newex="c";  # Give your new extension
for file in *.*;  # You can replace with *.txt instead of *.*
do 
 ex="${file##*.}";    # This retrieves the file extension
 ne=$(echo "$file" | sed -e "s|$ex|$newex|g"); # Replaces current with the new one
 echo "$ex";echo "$ne";
 mv "$file" "$ne";
done

我不应该使用任何循环或语句,只能使用管道、命令行和sed。 - heythatsmekri

3

您可以使用find查找所有文件,然后将其导入到while read循环中:

$ find . -name "*.ext1" -print0 | while read -d $'\0' file
do
   mv $file "${file%.*}.ext2"
done
${file%.*} 是小的右侧模式过滤器。百分号%标记要从右侧删除的模式(匹配最小的glob模式),.*是模式(最后一个.后面的字符)。 -print0会使用NUL字符而不是\n分隔文件名。-d $'\0'将读取以NUL字符分隔的文件名,这样,具有空格、制表符、\n或其他奇怪字符的文件名将被正确处理。

这不是一个循环吗?OP 不想要任何循环! - iamauser
这是一个管道。正如OP所说的“_所以我必须使用管道和sed命令来完成所有操作_”。我不确定OP在使用for时遇到了什么问题,但是由于循环解析参数的方式,for可能会有些棘手。不幸的是,OP没有提供太多关于他们正在做什么的信息。如果有更多信息,我可以给出更好的答案。 - David W.
同意您的观点,OP没有提供足够的信息,为什么不使用循环! - iamauser

2
你可以尝试以下选项: 选项1 使用findrename命令。
find . -type f -name "*.ext1" -exec rename -f 's/\.ext1$/ext2/' {} \;

选项 2 使用 findmv 命令

find . -type f -name "*.ext1" -exec sh -c 'mv -f $0 ${0%.ext1}.ext2' {} \;

注意:观察到许多终端不支持rename


@iamauser 如果 rename 无法工作,请尝试使用选项2的 mv。即使我也不确定为什么许多终端无法使用 rename。对于我来说,在 ubuntu 中可以工作,但在 RHEL 中不行。 - jkshah

2

使用sed和sh的另一种解决方案

printf "%s\n" *.ext1 | 
sed "s/'/'\\\\''/g"';s/\(.*\)'ext1'/mv '\''\1'ext1\'' '\''\1'ext2\''/g' | 
sh

为了更好的性能:只创建一个进程。
perl -le '($e,$f)=@ARGV;map{$o=$_;s/$e$/$f/;rename$o,$_}<*.$e>' ext2 ext3

0

好的,这应该可以工作。

mv $file $(echo $file | sed -E -e 's/.xml.bak.*/.xml/g' | sed -E -e 's/.\///g')

输出

abc.xml.bak.foobar -> abc.xml

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接