下面的代码有什么问题?

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

就像这样,我得到的字面值字符串$filename | cut -f1 -d'。',但如果我删除引号,我什么也得不到。与此同时,打字

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

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


当前回答

之前提供的答案在包含点的路径上有问题。一些例子:

/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

其他回答

正如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)

假设你的文件有。new扩展名

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

由于张贴后不显示特别报价,请参阅图片。

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

所以直线是

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

代码的解释:

Echo获取变量$filename的值并将其发送到标准输出 然后获取输出并将其输送到cut命令 切割将使用。作为分隔符(也称为分隔符),用于将字符串切割成段,并通过-f选择希望在输出中出现的段 然后$()命令替换将获得输出并返回其值 返回值将被赋给名为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

在Zsh:

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

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

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

它可以与其他类似的修饰语结合使用。

你的代码有两个问题:

您使用' (tick)而不是'(反tick)来包围生成想要存储在变量中的字符串的命令。 您没有将变量“$filename”“echo”到管道中的“cut”命令中。

我会把你的代码改为"name= ' echo $filename | cut -f 1 -d '。' ' ",如下所示(再次注意,后面的勾号围绕着name变量定义):

$> filename=foo.txt
$> echo $filename
foo.txt
$> name=`echo $filename | cut -f1 -d'.'`
$> echo $name
foo
$>