给定一个字符串文件路径,例如/foo/fizzbuzz。酒吧,我如何使用bash提取只是fizzbuzz部分说的字符串?


看看basename命令:

NAME="$(basename /foo/fizzbuzz.bar .bar)"

指示它删除后缀.bar,结果是NAME=fizzbuzz


纯粹的bash方式:

~$ x="/foo/bar/fizzbuzz.bar.quux.zoom"; 
~$ y=${x/\/*\//}; 
~$ echo ${y/.*/}; 
fizzbuzz

这个功能在man bash的“参数扩展”中有解释。非bash方法有很多:awk、perl、sed等等。

EDIT:用于文件后缀中的点,不需要知道后缀(扩展名),但不用于名称本身中的点。


perl -pe 's/\..*$//;s{^.*/}{}'

basename和dirname函数是你需要的:

mystring=/foo/fizzbuzz.bar
echo basename: $(basename "${mystring}")
echo basename + remove .bar: $(basename "${mystring}" .bar)
echo dirname: $(dirname "${mystring}")

输出:

basename: fizzbuzz.bar
basename + remove .bar: fizzbuzz
dirname: /foo

下面是如何在Bash中使用#和%操作符。

$ x="/foo/fizzbuzz.bar"
$ y=${x%.bar}
$ echo ${y##*/}
fizzbuzz

$ {x %。Bar}也可以是${x%。*}删除点或${x%%之后的所有内容。*}删除第一个点之后的所有内容。

例子:

$ x="/foo/fizzbuzz.bar.quux"
$ y=${x%.*}
$ echo $y
/foo/fizzbuzz.bar
$ y=${x%%.*}
$ echo $y
/foo/fizzbuzz

相关文档可以在Bash手册中找到。查找${parameter%word}和${parameter%%word}后面部分匹配的section。


使用basename假设您知道文件扩展名是什么,不是吗?

而且我相信各种正则表达式建议不能处理包含多个“”的文件名。

下面的内容似乎可以解决双点问题。哦,还有本身包含“/”的文件名(只是为了好玩)

用帕斯卡尔的话来说,“对不起,这个脚本太长了。我没有时间把它缩短。”


  #!/usr/bin/perl
  $fullname = $ARGV[0];
  ($path,$name) = $fullname =~ /^(.*[^\\]\/)*(.*)$/;
  ($basename,$extension) = $name =~ /^(.*)(\.[^.]*)$/;
  print $basename . "\n";
 

如果你不能像其他文章中建议的那样使用basename,你总是可以使用sed。这里有一个(丑陋的)例子。它不是最好的,但它的工作原理是提取所需的字符串并将输入替换为所需的字符串。

echo '/foo/fizzbuzz.bar' | sed 's|.*\/\([^\.]*\)\(\..*\)$|\1|g'

哪一个会得到输出

嘶嘶声


basename会移除路径。它还将删除给定的后缀,如果它与文件的后缀匹配,但您需要知道为命令提供的后缀。否则,你可以用mv,用其他方法找出新名称。


注意建议的perl解决方案:它删除第一个点之后的任何内容。

$ echo some.file.with.dots | perl -pe 's/\..*$//;s{^.*/}{}'
some

如果你想用perl来做,这是可行的:

$ echo some.file.with.dots | perl -pe 's/(.*)\..*$/$1/;s{^.*/}{}'
some.file.with

但如果使用Bash,则y=${x%。*}(或者basename "$x" .ext,如果你知道扩展名的话)要简单得多。


使用basename我使用以下方法来实现这一点:

for file in *; do
    ext=${file##*.}
    fname=`basename $file $ext`

    # Do things with $fname
done;

这不需要对文件扩展名的先验知识,即使你的文件名中有点(在它的扩展名前面)也可以工作;虽然它确实需要程序基名,但这是GNU coreutils的一部分,所以它应该随任何发行版一起发布。


纯bash,在两个独立的操作中完成:

从路径字符串中移除路径: 路径= / foo / bar / bim /巴兹/ file.gif 路径文件= $ {# # * /} #$file现在是file.gif 从路径字符串中移除扩展名: 基础= ${文件%。*} #${base}现在是“文件”。


将排名第一的答案与排名第二的答案结合起来,得到没有完整路径的文件名:

$ x="/foo/fizzbuzz.bar.quux"
$ y=(`basename ${x%%.*}`)
$ echo $y
fizzbuzz

除了这个答案中使用的POSIX符合语法外,

basename string [suffix]

就像在

basename /foo/fizzbuzz.bar .bar

GNU basename支持另一种语法:

basename -s .bar /foo/fizzbuzz.bar

同样的结果。区别和优势在于-s意味着-a,它支持多个参数:

$ basename -s .bar /foo/fizzbuzz.bar /baz/foobar.bar
fizzbuzz
foobar

这甚至可以通过使用-z选项将输出与NUL字节分开来实现文件名安全,例如对于这些包含空格,换行符和glob字符(由ls引用)的文件:

$ ls has*
'has'$'\n''newline.bar'  'has space.bar'  'has*.bar'

读入数组:

$ readarray -d $'\0' arr < <(basename -zs .bar has*)
$ declare -p arr
declare -a arr=([0]=$'has\nnewline' [1]="has space" [2]="has*")

readarray -d要求Bash 4.4或更新版本。对于旧版本,我们必须循环:

while IFS= read -r -d '' fname; do arr+=("$fname"); done < <(basename -zs .bar has*)

你可以使用

mv *<PATTERN>.jar "$(basename *<PATTERN>.jar <PATTERN>.jar).jar"

例如:-我想从我的文件名中删除- snapshot。用于下面的命令

 mv *-SNAPSHOT.jar "$(basename *-SNAPSHOT.jar -SNAPSHOT.jar).jar"

如果您想只保留带扩展名的文件名并删除文件路径

$ x="myfile/hello/foo/fizzbuzz.bar"
$ echo ${x##*/}
$ fizzbuzz.bar

Bash手册中的解释,请参见${parameter##word}