bash 如何删除文件的扩展名?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/17843889/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to remove the extension of a file?
提问by bashboy
I have a folder that is full of .bak files and some other files also. I need to remove the extension of all .bak files in that folder. How do I make a command which will accept a folder name and then remove the extension of all .bak files in that folder ?
我有一个充满 .bak 文件和其他一些文件的文件夹。我需要删除该文件夹中所有 .bak 文件的扩展名。如何创建一个命令来接受文件夹名称,然后删除该文件夹中所有 .bak 文件的扩展名?
Thanks.
谢谢。
回答by Jeff Bowman
To remove a string from the end of a BASH variable, use the ${var%ending}
syntax. It's one of a number of string manipulations available to you in BASH.
要从 BASH 变量的末尾删除字符串,请使用${var%ending}
语法。它是您在 BASH 中可用的众多字符串操作之一。
Use it like this:
像这样使用它:
# Run in the same directory as the files
for FILENAME in *.bak; do mv "$FILENAME" "${FILENAME%.bak}"; done
That works nicely as a one-liner, but you could also wrap it as a script to work in an arbitrary directory:
这作为单行程序很好用,但您也可以将其包装为脚本以在任意目录中工作:
# If we're passed a parameter, cd into that directory. Otherwise, do nothing.
if [ -n "" ]; then
cd ""
fi
for FILENAME in *.bak; do mv "$FILENAME" "${FILENAME%.bak}"; done
Note that while quoting your variables is almost always a good practice, the for FILENAME in *.bak
is still dangerous if any of your filenames might contain spaces. Read David W.'s answer for a more-robust solution, and this documentfor alternative solutions.
请注意,虽然引用您的变量几乎总是一个好习惯,但for FILENAME in *.bak
如果您的任何文件名可能包含空格,这仍然是危险的。阅读David W.的答案以获得更强大的解决方案,以及本文档的替代解决方案。
回答by David W.
There are several ways to remove file suffixes:
有几种方法可以删除文件后缀:
In BASH and Kornshell, you can use the environment variable filtering. Search for ${parameter%word}
in the BASH manpagefor complete information. Basically, #
is a left filterand %
is a rightfilter. You can remember this because #
is to the left of %
.
在 BASH 和 Kornshell 中,您可以使用环境变量过滤。${parameter%word}
在 BASH联机帮助页中搜索以获取完整信息。基本上,#
是左过滤器,%
是右过滤器。您可以记住这一点,因为#
位于 的左侧%
。
If you use a double filter (i.e. ##
or %%
, you are trying to filter on the biggest match. If you have a single filter (i.e. #
or %
, you are trying to filter on the smallest match.
如果您使用双过滤器(即##
或%%
,您正在尝试过滤最大的匹配项。如果您有一个过滤器(即#
或%
,您尝试过滤最小的匹配项。
What matches is filteredout and you get the rest of the string:
匹配的内容被过滤掉,你会得到字符串的其余部分:
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"
Notice this is a globmatch and not a regular expression match!. If you want to remove a file suffix:
请注意,这是一个全局匹配而不是正则表达式匹配!。如果要删除文件后缀:
file_sans_ext=${file%.*}
The .*
will match on the period and all characters after it. Since it is a single %
, it will match on the smallest globon the right side of the string. If the filter can't match anything, it the same as your original string.
在.*
将匹配期间和之后的所有字符。由于它是单个%
,它将匹配字符串右侧的最小glob。如果过滤器无法匹配任何内容,则它与您的原始字符串相同。
You can verify a file suffix with something like this:
您可以使用以下内容验证文件后缀:
if [ "${file}" != "${file%.bak}" ]
then
echo "$file is a type '.bak' file"
else
echo "$file is not a type '.bak' file"
fi
Or you could do this:
或者你可以这样做:
file_suffix=$(file##*.}
echo "My file is a file '.$file_suffix'"
Note that this will remove the period of the file extension.
请注意,这将删除文件扩展名的句点。
Next, we will loop:
接下来,我们将循环:
find . -name "*.bak" -print0 | while read -d $'$ bash find.out
' file
do
echo "mv '$file' '${file%.bak}'"
done | tee find.out
The find
command finds the files you specify. The -print0
separates out the names of the files with a NUL symbol -- which is one of the few characters not allowed in a file name. The -d $
\0means that your input separators are NUL symbols. See how nicely the
find -print0and
read -d $'\0'` together?
该find
命令会查找您指定的文件。该-print0
分离出一个NUL符号的文件的名称-这是一个文件名,不允许少数人物之一。该-d $
\ 0means that your input separators are NUL symbols. See how nicely the
找到-print0and
读-d $'\ 0'`在一起吗?
You should almost never use the for file in $(*.bak)
method. This will fail if the files have any white space in the name.
您几乎不应该使用该for file in $(*.bak)
方法。如果文件名称中有任何空格,这将失败。
Notice that this command doesn't actually move any files. Instead, it produces a find.out
file with a list of all the file renames. You should always do something like this when you do commands that operate on massive amounts of files just to be sure everything is fine.
请注意,此命令实际上并未移动任何文件。相反,它会生成一个find.out
包含所有重命名文件的列表的文件。当您执行对大量文件进行操作的命令时,您应该总是这样做,以确保一切正常。
Once you've determined that all the commands in find.out
are correct, you can run it like a shell script:
一旦确定所有命令find.out
都正确,就可以像 shell 脚本一样运行它:
#!/bin/bash
cd ""
for i in *.bak ; do mv -f "$i" "${i%%.bak}" ; done
回答by jxh
Caveat: there is no error checking:
警告:没有错误检查:
for FILENAME in `find . -name "*.bak"`; do mv --force "$FILENAME" "${FILENAME%.bak}"; done
回答by Yaakov
rename .bak '' *.bak
rename .bak '' *.bak
(rename
is in the util-linux
package)
(rename
在util-linux
包裹里)
回答by Matt
You can always use the find command to get all the subdirectories
您可以随时使用 find 命令获取所有子目录
##代码##