4

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

谢谢。

4

5 回答 5

8

要从 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.的答案以获得更强大的解决方案,并阅读本文档以获得替代解决方案。

于 2013-07-24T20:16:05.910 回答
6

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

在 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命令查找您指定的文件。用-print0NUL 符号分隔文件名——这是文件名中不允许出现的少数字符之一。-d $\0 means that your input separators are NUL symbols. See how nicely thefind -print0 andread -d $'\0'` 一起?

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

请注意,此命令实际上并不移动任何文件。相反,它会生成一个find.out包含所有文件重命名列表的文件。当您执行对大量文件进行操作的命令时,您应该始终这样做,以确保一切正常。

一旦确定其中的所有命令find.out都正确,就可以像运行 shell 脚本一样运行它:

$ bash find.out
于 2013-07-24T21:05:47.240 回答
2

rename .bak '' *.bak

renameutil-linux包装内)

于 2013-07-25T00:15:50.893 回答
1

警告:没有错误检查:

#!/bin/bash
cd "$1"
for i in *.bak ; do mv -f "$i" "${i%%.bak}" ; done
于 2013-07-24T20:14:42.653 回答
0

您始终可以使用 find 命令获取所有子目录

for FILENAME in `find . -name "*.bak"`; do mv --force "$FILENAME" "${FILENAME%.bak}"; done
于 2013-11-19T06:12:06.497 回答