我有一个充满 .bak 文件和其他一些文件的文件夹。我需要删除该文件夹中所有 .bak 文件的扩展名。如何创建一个接受文件夹名称的命令,然后删除该文件夹中所有 .bak 文件的扩展名?
谢谢。
要从 BASH 变量的末尾删除字符串,请使用${var%ending}
语法。它是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.的答案以获得更强大的解决方案,并阅读本文档以获得替代解决方案。
有几种方法可以删除文件后缀:
在 BASH 和 Kornshell 中,您可以使用环境变量过滤。${parameter%word}
在 BASH 手册页中搜索以获取完整信息。基本上,#
是左滤波器,%
也是右滤波器。您可以记住这一点,因为#
它位于 的左侧%
。
如果您使用双过滤器(即##
or %%
,您正在尝试过滤最大的匹配项。如果您使用单个过滤器(即#
or %
,您正在尝试过滤最小的匹配项。
什么匹配被过滤掉,你得到字符串的其余部分:
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 $
\0 means that your input separators are NUL symbols. See how nicely the
find -print0 and
read -d $'\0'` 一起?
您几乎不应该使用该for file in $(*.bak)
方法。如果文件名称中有任何空格,这将失败。
请注意,此命令实际上并不移动任何文件。相反,它会生成一个find.out
包含所有文件重命名列表的文件。当您执行对大量文件进行操作的命令时,您应该始终这样做,以确保一切正常。
一旦确定其中的所有命令find.out
都正确,就可以像运行 shell 脚本一样运行它:
$ bash find.out
rename .bak '' *.bak
(rename
在util-linux
包装内)
警告:没有错误检查:
#!/bin/bash
cd "$1"
for i in *.bak ; do mv -f "$i" "${i%%.bak}" ; done
您始终可以使用 find 命令获取所有子目录
for FILENAME in `find . -name "*.bak"`; do mv --force "$FILENAME" "${FILENAME%.bak}"; done