214

以下代码有什么问题?

name='$filename | cut -f1 -d'.''

照原样,我得到了文字 string $filename | cut -f1 -d'.',但是如果我删除引号,我什么也得不到。同时,键入

"test.exe" | cut -f1 -d'.'

在 shell 中给了我想要的输出,test. 我已经知道$filename已经分配了正确的值。我想要做的是将不带扩展名的文件名分配给变量。

4

15 回答 15

393

您还可以使用参数扩展:

$ filename=foo.txt
$ echo "${filename%.*}"
foo

请注意,如果没有文件扩展名,它将进一步向后查找点,例如

  • 如果文件名仅以点开头(例如.bashrc),它将删除整个文件名。
  • 如果路径中只有一个点(例如path.to/myfile./myfile),那么它将在路径内修剪。
于 2012-08-28T04:55:25.567 回答
167

当您想在脚本/命令中执行命令时,您应该使用命令替换语法。$(command)

所以你的线是

name=$(echo "$filename" | cut -f 1 -d '.')

代码说明:

  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
于 2012-08-28T04:10:56.783 回答
159

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

$ basename /home/jsmith/base.wiki .wiki
base
于 2015-05-02T21:49:17.730 回答
36

如果您的文件名包含一个点(扩展名除外),则使用此:

echo $filename | rev | cut -f 2- -d '.' | rev
于 2015-09-15T11:31:42.867 回答
26
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

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

于 2016-04-26T13:13:34.983 回答
21

仅使用 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 "$oneextless" 

# 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"

打印演示:

this.path/with.dots/in.path.name/filename.tar.gz
this.path/with.dots/in.path.name
filename.tar.gz
filename.tar
filename
于 2020-09-19T15:37:11.323 回答
8
#!/bin/bash
file=/tmp/foo.bar.gz
echo $file ${file%.*}

输出:

/tmp/foo.bar.gz /tmp/foo.bar

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

于 2018-06-05T23:13:32.777 回答
3

我的建议是使用basename.
它在 Ubuntu 中是默认的,视觉上简单的代码并处理大多数情况。

以下是一些处理空格和多点/子扩展的子案例:

pathfile="../space fld/space -file.tar.gz"
echo ${pathfile//+(*\/|.*)}

它通常从一开始就摆脱扩展,但在我们的道路.上失败了..

echo **"$(basename "${pathfile%.*}")"**  
space -file.tar     # I believe we needed exatly that

这是一个重要的注意事项:

我在双引号内使用双引号来处理空格。由于向 $ 发送短信,单引号不会通过。Bash 是不寻常的,并且由于扩展而读取“第二个“第一个”引号。

但是,您仍然需要考虑.hidden_files

hidden="~/.bashrc"
echo "$(basename "${hidden%.*}")"  # will produce "~" !!!  

不是预期的“”结果。为了使它发生使用$HOME/home/user_path/
因为 bash 再次“不寻常”并且不要扩展“~”(搜索 bash BashPitfalls)

hidden2="$HOME/.bashrc" ;  echo '$(basename "${pathfile%.*}")'
于 2019-03-06T07:55:58.943 回答
2

以前提供的答案在包含点的路径方面存在问题。一些例子:

/xyz.dir/file.ext
./file.ext
/a.b.c/x.ddd.txt

我更喜欢使用|sed -e 's/\.[^./]*$//'. 例如:

$ echo "/xyz.dir/file.ext" | sed -e 's/\.[^./]*$//'
/xyz.dir/file
$ echo "./file.ext" | sed -e 's/\.[^./]*$//'
./file
$ echo "/a.b.c/x.ddd.txt" | sed -e 's/\.[^./]*$//'
/a.b.c/x.ddd

注意:如果要删除多个扩展名(如上一个示例),请使用|sed -e 's/\.[^/]*$//'

$ echo "/a.b.c/x.ddd.txt" | sed -e 's/\.[^/]*$//'
/a.b.c/x

但是,此方法将在没有扩展名的“点文件”中失败:

$ echo "/a.b.c/.profile" | sed -e 's/\.[^./]*$//'
/a.b.c/

要涵盖此类情况,您可以使用:

$ echo "/a.b.c/.profile" | sed -re 's/(^.*[^/])\.[^./]*$/\1/'
/a.b.c/.profile
于 2020-09-13T10:57:46.297 回答
1
#!/bin/bash
filename=program.c
name=$(basename "$filename" .c)
echo "$name"

输出:

program
于 2018-04-28T21:44:33.883 回答
1

正如 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)
于 2018-08-30T11:08:56.337 回答
1

这个涵盖了所有的可能性!(路径中的点与否;有扩展名或无扩展名):

tmp1=${filename##*/};tmp2=${tmp1:1};filename_noextension=$(echo -n ${tmp1:0:1};echo ${tmp2%.*});echo $filename_noextension

笔记:

  • 它为您提供不带任何扩展名的文件名。所以$filename_noextension变量中没有路径。
  • 您最终会得到两个不需要的变量$tmp1$tmp2. 确保您没有在脚本中使用它们。

测试示例:

filename=.bashrc; echo "filename: $filename"; tmp1=${filename##*/};tmp2=${tmp1:1};filename_noextension=$(echo -n ${tmp1:0:1};echo ${tmp2%.*}); echo "filename without extension: $filename_noextension"

filename=.bashrc.txt; echo "filename: $filename"; tmp1=${filename##*/};tmp2=${tmp1:1};filename_noextension=$(echo -n ${tmp1:0:1};echo ${tmp2%.*}); echo "filename without extension: $filename_noextension"

filename=.bashrc.txt.tar; echo "filename: $filename"; tmp1=${filename##*/};tmp2=${tmp1:1};filename_noextension=$(echo -n ${tmp1:0:1};echo ${tmp2%.*}); echo "filename without extension: $filename_noextension"

filename=~/.bashrc; echo "filename: $filename"; tmp1=${filename##*/};tmp2=${tmp1:1};filename_noextension=$(echo -n ${tmp1:0:1};echo ${tmp2%.*}); echo "filename without extension: $filename_noextension"

filename=~/.bashrc.txt.tar; echo "filename: $filename"; tmp1=${filename##*/};tmp2=${tmp1:1};filename_noextension=$(echo -n ${tmp1:0:1};echo ${tmp2%.*}); echo "filename without extension: $filename_noextension"

filename=bashrc; echo "filename: $filename"; tmp1=${filename##*/};tmp2=${tmp1:1};filename_noextension=$(echo -n ${tmp1:0:1};echo ${tmp2%.*}); echo "filename without extension: $filename_noextension"

filename=bashrc.txt; echo "filename: $filename"; tmp1=${filename##*/};tmp2=${tmp1:1};filename_noextension=$(echo -n ${tmp1:0:1};echo ${tmp2%.*}); echo "filename without extension: $filename_noextension"

filename=bashrc.txt.tar; echo "filename: $filename"; tmp1=${filename##*/};tmp2=${tmp1:1};filename_noextension=$(echo -n ${tmp1:0:1};echo ${tmp2%.*}); echo "filename without extension: $filename_noextension"

filename=~/bashrc; echo "filename: $filename"; tmp1=${filename##*/};tmp2=${tmp1:1};filename_noextension=$(echo -n ${tmp1:0:1};echo ${tmp2%.*}); echo "filename without extension: $filename_noextension"

filename=~/bashrc.txt.tar; echo "filename: $filename"; tmp1=${filename##*/};tmp2=${tmp1:1};filename_noextension=$(echo -n ${tmp1:0:1};echo ${tmp2%.*}); echo "filename without extension: $filename_noextension"

于 2021-02-12T19:06:55.463 回答
0

您的代码有两个问题:

  1. 您使用 '(勾号)而不是 `(反勾号)来包围生成要存储在变量中的字符串的命令。
  2. 您没有将变量“$filename”“回显”到“cut”命令中。

我会将您的代码更改为“name=`echo $filename | cut -f 1 -d '。” `",如下所示(再次注意名称变量定义周围的反引号):

$> filename=foo.txt
$> echo $filename
foo.txt
$> name=`echo $filename | cut -f1 -d'.'`
$> echo $name
foo
$> 
于 2016-07-28T00:10:32.403 回答
0

在 Zsh 中:

fullname=bridge.zip
echo ${fullname:r}

它简单、干净,并且可以链接以删除多个扩展:

fullname=bridge.tar.gz
echo ${fullname:r:r}

并且可以与其他类似的修饰符组合使用。

于 2022-02-15T09:55:17.733 回答
-1

在此处输入图像描述

假设您的文件具有 .new 扩展名

ls -1 | awk '{ print "mv "$1" `basename "$1" .new`"}' | sh

由于发布后没有显示特殊报价,请查看图片。

于 2021-05-01T15:17:30.880 回答