下面的代码有什么问题?

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

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

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

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


当前回答

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

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

其他回答

你也可以使用参数展开:

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

只是要注意,如果没有文件扩展名,它将进一步向后寻找点,例如。

如果文件名只是以点开始(例如。bashrc),它将删除整个文件名。 如果只在路径中有一个点(例如path。到/myfile或。/myfile),那么它将在路径内部进行修剪。

如果你的文件名包含一个点(除了扩展名),那么使用这个:

echo $filename | rev | cut -f 2- -d '.' | rev

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

/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)

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

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