bash 如何在 shell 脚本中删除文件名的扩展名?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/12152626/
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 can I remove the extension of a filename in a shell script?
提问by mimicocotopus
What's wrong with the following code?
以下代码有什么问题?
name='$filename | cut -f1 -d'.''
As is, I get the literal string $filename | cut -f1 -d'.'
, but if I remove the quotes I don't get anything. Meanwhile, typing
按原样,我得到文字 string $filename | cut -f1 -d'.'
,但如果我删除引号,我什么也得不到。同时,键入
"test.exe" | cut -f1 -d'.'
in a shell gives me the output I want, test
. I already know $filename
has been assigned the right value. What I want to do is assign to a variable the filename without the extension.
在 shell 中给了我我想要的输出,test
. 我已经知道$filename
已经分配了正确的值。我想要做的是将没有扩展名的文件名分配给变量。
采纳答案by Rohan
You should be using the command substitutionsyntax $(command)
when you want to execute a command in script/command.
当您想在脚本/命令中执行命令时,您应该使用命令替换语法$(command)
。
So your line would be
所以你的线路将是
name=$(echo "$filename" | cut -f 1 -d '.')
Code explanation:
代码说明:
echo
get the value of the variable$filename
and send it to standard output- We then grab the output and pipe it to the
cut
command - The
cut
will use the . as delimiter (also known as separator) for cutting the string into segments and by-f
we select which segment we want to have in output - Then the
$()
command substitution will get the output and return its value - The returned value will be assigned to the variable named
name
echo
获取变量的值$filename
并将其发送到标准输出- 然后我们获取输出并将其通过管道传递给
cut
命令 - 该
cut
会使用。作为分隔符(也称为分隔符),用于将字符串切割成段,并通过-f
我们选择我们想要在输出中包含的段 - 然后
$()
命令替换将获得输出并返回其值 - 返回值将分配给名为的变量
name
Note that this gives the portion of the variable up to the first period .
:
请注意,这给出了直到第一个周期的变量部分.
:
$ filename=hello.world
$ echo "$filename" | cut -f 1 -d '.'
hello
$ filename=hello.hello.hello
$ echo "$filename" | cut -f 1 -d '.'
hello
$ filename=hello
$ echo "$filename" | cut -f 1 -d '.'
hello
回答by chepner
You can also use parameter expansion:
您还可以使用参数扩展:
$ filename=foo.txt
$ echo "${filename%.*}"
foo
回答by Steven Penny
回答by Raghwendra
file1=/tmp/main.one.two.sh
t=$(basename "$file1") # output is main.one.two.sh
name=$(echo "$file1" | sed -e 's/\.[^.]*$//') # output is /tmp/main.one.two
name=$(echo "$t" | sed -e 's/\.[^.]*$//') # output is main.one.two
use whichever you want. Here I assume that last .
(dot) followed by text is extension.
使用任何你想要的。在这里,我假设最后一个.
(点)后跟文本是扩展名。
回答by manish_s
If your filename contains a dot (other than the one of the extension) then use this:
如果您的文件名包含一个点(扩展名除外),请使用以下命令:
echo $filename | rev | cut -f 2- -d '.' | rev
回答by C. Paul Bond
#!/bin/bash
file=/tmp/foo.bar.gz
echo $file ${file%.*}
outputs:
输出:
/tmp/foo.bar.gz /tmp/foo.bar
Note that only the last extension is removed.
请注意,仅删除了最后一个扩展名。
回答by Alexey K.
My recommendation is to use basename
.
It is by default in Ubuntu, visually simple code and deal with majority of cases.
我的建议是使用basename
.
它默认在 Ubuntu 中,视觉上简单的代码并处理大多数情况。
Here are some sub-cases to deal with spaces and multi-dot/sub-extension:
以下是处理空格和多点/子扩展的一些子案例:
pathfile="../space fld/space -file.tar.gz"
echo ${pathfile//+(*\/|.*)}
It usually get rid of extension from first .
, but fail in our ..
path
它通常从一开始就摆脱了扩展.
,但在我们的..
道路上失败了
echo **"$(basename "${pathfile%.*}")"**
space -file.tar # I believe we needed exatly that
Here is an important note:
这里有一个重要的注意事项:
I used double quotes inside double quotes to deal with spaces. Single quote will not pass due to texting the $. Bash is unusual and reads "second "first" quotes" due to expansion.
我在双引号内使用双引号来处理空格。由于发短信 $,单引号不会通过。Bash 是不寻常的,并且由于扩展而读取“第二个“第一个”引号。
However, you still need to think of .hidden_files
但是,您仍然需要考虑 .hidden_files
hidden="~/.bashrc"
echo "$(basename "${hidden%.*}")" # will produce "~" !!!
not the expected "" outcome. To make it happen use $HOME
or /home/user_path/
because again bash is "unusual" and don't expand "~" (search for bash BashPitfalls)
不是预期的“”结果。为了让它发生,$HOME
或者/home/user_path/
因为 bash 是“不寻常的”并且不要扩展“~”(搜索 bash BashPitfalls)
hidden2="$HOME/.bashrc" ; echo '$(basename "${pathfile%.*}")'
回答by booboo
#!/bin/bash
filename=program.c
name=$(basename "$filename" .c)
echo "$name"
outputs:
输出:
program
回答by MadMage
As pointed out by Hawker65 in the comment of chepner answer, the most voted solution does neither take care of multiple extensions (such as filename.tar.gz), nor of dots in the rest of the path (such as this.path/with.dots/in.path.name). A possible solution is:
正如 Hawker65 在 chepner answer 的评论中指出的那样,投票最多的解决方案既不处理多个扩展名(例如 filename.tar.gz),也不处理路径其余部分中的点(例如 this.path/with .dots/in.path.name)。一个可能的解决方案是:
a=this.path/with.dots/in.path.name/filename.tar.gz
echo $(dirname $a)/$(basename $a | cut -d. -f1)
回答by FanDeLaU
Two problems with your code:
您的代码有两个问题:
- You used a ' (tick) instead of a ` (back tick) to surround the commands that generate the string you want to store in the variable.
- You didn't "echo" the variable "$filename" to the pipe into the "cut" command.
- 您使用 '(勾号)而不是 `(反勾号)来包围生成要存储在变量中的字符串的命令。
- 您没有将变量“$filename”“回显”到管道中的“cut”命令中。
I'd change your code to "name=`echo $filename | cut -f 1 -d '.' `", as shown below (again, notice the back ticks surrounding the name variable definition):
我会将您的代码更改为“name=`echo $filename | cut -f 1 -d '。” `",如下所示(再次注意名称变量定义周围的反引号):
$> filename=foo.txt
$> echo $filename
foo.txt
$> name=`echo $filename | cut -f1 -d'.'`
$> echo $name
foo
$>