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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 22:36:52  来源:igfitidea点击:

How can I remove the extension of a filename in a shell script?

bashshellshcutgnu-coreutils

提问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 $filenamehas 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:

代码说明:

  1. echoget the value of the variable $filenameand send it to standard output
  2. We then grab the output and pipe it to the cutcommand
  3. The cutwill use the . as delimiter (also known as separator) for cutting the string into segments and by -fwe select which segment we want to have in output
  4. Then the $()command substitution will get the output and return its value
  5. The returned value will be assigned to the variable named name
  1. echo获取变量的值$filename并将其发送到标准输出
  2. 然后我们获取输出并将其通过管道传递给cut命令
  3. cut会使用。作为分隔符(也称为分隔符),用于将字符串切割成段,并通过-f我们选择我们想要在输出中包含的段
  4. 然后$()命令替换将获得输出并返回其值
  5. 返回值将分配给名为的变量 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

If you know the extension, you can use basename

如果您知道扩展名,则可以使用basename

$ basename /home/jsmith/base.wiki .wiki
base

回答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 $HOMEor /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:

您的代码有两个问题:

  1. You used a ' (tick) instead of a ` (back tick) to surround the commands that generate the string you want to store in the variable.
  2. You didn't "echo" the variable "$filename" to the pipe into the "cut" command.
  1. 您使用 '(勾号)而不是 `(反勾号)来包围生成要存储在变量中的字符串的命令。
  2. 您没有将变量“$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
$>