2013-07-24 322 views
4

我有一个充满.bak文件和一些其他文件的文件夹。我需要删除该文件夹中所有.bak文件的扩展名。如何创建一个接受文件夹名称的命令,然后删除该文件夹中所有.bak文件的扩展名?如何删除文件的扩展名?

谢谢。

回答

8

要从BASH可变的末端除去一个字符串,可使用${var%ending}语法。这是a number of string manipulations available to you in BASH之一。

使用这样的:

# Run in the same directory as the files 
for FILENAME in *.bak; do mv "$FILENAME" "${FILENAME%.bak}"; done 

这很好地工作作为一个内胆,但你也可以把它包装成一个脚本在任意目录下工作:

# If we're passed a parameter, cd into that directory. Otherwise, do nothing. 
if [ -n "$1" ]; then 
    cd "$1" 
fi 
for FILENAME in *.bak; do mv "$FILENAME" "${FILENAME%.bak}"; done 

注意虽然引用变量几乎总是一个好习惯,但如果任何文件名可能包含空格,则for FILENAME in *.bak仍然很危险。阅读David W.的答案是更强大的解决方案,而this document是替代解决方案。

+0

如果文件名中有空格,该怎么办? –

+0

谢谢。这很好。我可以让这个命令为任何目录执行任务吗?我不想一直光盘进入目录。 – bashboy

+0

btw,完成的含义是什么? – bashboy

1

警告:没有错误检查:

#!/bin/bash 
cd "$1" 
for i in *.bak ; do mv -f "$i" "${i%%.bak}" ; done 
+0

你的脚本没有工作,也挂着我的目录结构。 – bashboy

+0

@bashboy:您的文件名中可能有空格?我修改了脚本以尝试解释它。 – jxh

6

有几种方法可以删除文件后缀:

在bash和Kornshell,您可以使用环境变量过滤。在BASH manpage中搜索${parameter%word}以获取完整信息。基本上,#左侧过滤器%右侧过滤器。您可以记住这一点,因为#位于%的左侧。

如果您使用的是双滤光片(即##%%,你想上最重要的比赛进行筛选。如果你有一个单一的过滤器(即#%,你想上最小的匹配过滤器。

匹配什么是过滤出来,你得到的字符串的其余部分:

file="this/is/my/file/name.txt" 
echo ${file#*/} #Matches is "this/` and will print out "is/my/file/name.txt" 
echo ${file##*/} #Matches "this/is/my/file/" and will print out "name.txt" 
echo ${file%/*} #Matches "/name.txt" and will print out "/this/is/my/file" 
echo ${file%%/*} #Matches "/is/my/file/name.txt" and will print out "this" 

请注意这是一个水珠比赛,而不是一个正则表达式匹配!如果你想牛逼Ø删除文件后缀:

file_sans_ext=${file%.*} 

.*将匹配期间和之后的所有字符。由于它是单个%,因此它将与字符串右侧的最小glob匹配。如果过滤器无法匹配任何内容,则与原始字符串相同。

您可以验证文件后缀像这样的东西:

if [ "${file}" != "${file%.bak}" ] 
then 
    echo "$file is a type '.bak' file" 
else 
    echo "$file is not a type '.bak' file" 
fi 

或者你可以这样做:

file_suffix=$(file##*.} 
echo "My file is a file '.$file_suffix'" 

注意,这将删除文件扩展名的时期。

下一步,我们将循环:

find . -name "*.bak" -print0 | while read -d $'\0' file 
do 
    echo "mv '$file' '${file%.bak}'" 
done | tee find.out 

find命令查找指定的文件。 -print0用NUL符号分隔文件的名称 - 这是文件名中不允许的几个字符之一。 -d $ \ means that your input separators are NUL symbols. See how nicely the find -print0 and读-d $'\ 0'`在一起?

你应该几乎从不使用for file in $(*.bak)方法。如果文件名称中有空格,这将失败。

请注意,该命令实际上并不移动任何文件。相反,它会生成一个带有所有文件重命名列表的find.out文件。当你执行大量文件的命令时,你应该总是这样做,以确保一切正常。

一旦你已经确定,在find.out所有的命令都是正确的,你可以像一个shell脚本运行:

$ bash find.out 
+0

+1用于解释,特别是'find.out'技术。在对文件系统做一些可能很丑陋的事情之前,这是一个非常好的方法来进行理智检查。 –

1

rename .bak '' *.bak

rename是在util-linux包)

0

您可以随时使用find命令获取所有子目录

for FILENAME in `find . -name "*.bak"`; do mv --force "$FILENAME" "${FILENAME%.bak}"; done