如何在shell脚本中删除文件名的扩展名?

mim*_*pus 121 bash shell cut sh gnu-coreutils

以下代码有什么问题?

name='$filename | cut -f1 -d'.''
Run Code Online (Sandbox Code Playgroud)

因为,我得到文字字符串$filename | cut -f1 -d'.',但如果我删除引号,我什么都没得到.同时打字

"test.exe" | cut -f1 -d'.'
Run Code Online (Sandbox Code Playgroud)

在shell中给我输出我想要的输出test.我已经知道$filename已经分配了正确的价值.我想要做的是为变量分配没有扩展名的文件名.

che*_*ner 212

您还可以使用参数扩展:

$ filename=foo.txt
$ echo "${filename%.*}"
foo
Run Code Online (Sandbox Code Playgroud)

  • `%.*`只会删除最后一个扩展名; 如果你想删除*all*扩展名,请使用`%%.*`. (9认同)
  • 这里是命令的解释:https://www.gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.html (6认同)
  • 这是否适用于具有多个扩展名的文件,例如“image.png.gz”? (3认同)
  • 请注意,如果没有扩展名并且路径是相对的,这将删除整个名称。例如,`filename=./ihavenoextension`。 (3认同)
  • 在这里我准备使用 `echo -n "This.File.Has.Periods.In.It.txt" | awk -F。'{$NF=""; 打印 $0}' | tr ' ' '.' | 转 | 切 -c 2- | 转速`。谢谢。 (2认同)

小智 99

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

$ basename /home/jsmith/base.wiki .wiki
base
Run Code Online (Sandbox Code Playgroud)

  • 如何仅删除“.wiki”并最终得到“/home/jsmith/base”? (2认同)

Roh*_*han 95

如果要在脚本/命令中执行命令,则应使用命令替换语法$(command).

所以你的路线就是

name=$(echo "$filename" | cut -f 1 -d '.')
Run Code Online (Sandbox Code Playgroud)

代码说明:

  1. echo获取变量的值$filename并将其发送到标准输出
  2. 然后我们获取输出并将其传递给cut命令
  3. cut会使用.作为分隔符(也称为分隔符),用于将字符串切割成段,并通过-f我们选择输出中要包含的段
  4. 然后$()命令替换将获得输出并返回其值
  5. 返回的值将分配给名为的变量 name

请注意,这会将变量的部分提供给第一个句点.:

$ 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
Run Code Online (Sandbox Code Playgroud)

  • 这个答案的问题是它假设输入字符串只有一个点... @chepner下面有一个更好的解决方案... name = $ {filename%.*} (30认同)
  • POSIX不推荐使用反引号,首选`$()`. (16认同)
  • 分叉和管道以获得几个字符是可以想象的最糟糕的解决方案. (3认同)
  • 这个答案是初学者的特征,不应散布。使用chepner的答案所述的内置机制 (3认同)
  • 就像其他答案一样,在“./ihavenoextension”上失败。 (2认同)

man*_*h_s 17

如果您的文件名包含一个点(扩展名除外),请使用以下命令:

echo $filename | rev | cut -f 2- -d '.' | rev
Run Code Online (Sandbox Code Playgroud)

  • 在我看来,这应该是公认的答案,因为它适用于带有点的路径,带有以点开头的隐藏文件,甚至带有多个扩展名的文件。 (3认同)
  • 像这样的文件会发生什么:`filename=/tmp.d/foo`? (2认同)
  • 它也有“点文件”的问题。例如,尝试使用“.profile”。 (2认同)

小智 17

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
Run Code Online (Sandbox Code Playgroud)

使用你想要的任何一个.这里我假设最后.(点)后跟文本是扩展名.


Léa*_*ris 13

仅使用 POSIX 的内置:

#!/usr/bin/env sh
path=this.path/with.dots/in.path.name/filename.tar.gz

# Get the basedir without external command
# by stripping out shortest trailing match of / followed by anything
dirname=${path%/*}

# Get the basename without external command
# by stripping out longest leading match of anything followed by /
basename=${path##*/}

# Strip uptmost trailing extension only
# by stripping out shortest trailing match of dot followed by anything
oneextless=${basename%.*}; echo "$noext" 

# Strip all extensions
# by stripping out longest trailing match of dot followed by anything
noext=${basename%%.*}; echo "$noext"

# Printout demo
printf %s\\n "$path" "$dirname" "$basename" "$oneextless" "$noext"
Run Code Online (Sandbox Code Playgroud)

打印演示:

this.path/with.dots/in.path.name/filename.tar.gz
this.path/with.dots/in.path.name
filename.tar.gz
filename.tar
filename
Run Code Online (Sandbox Code Playgroud)


小智 7

#!/bin/bash
file=/tmp/foo.bar.gz
echo $file ${file%.*}
Run Code Online (Sandbox Code Playgroud)

输出:

/tmp/foo.bar.gz /tmp/foo.bar
Run Code Online (Sandbox Code Playgroud)

请注意,仅删除了最后一个扩展名。

  • 像这样的文件会发生什么:`file=/tmp.d/foo`? (3认同)