给定一个字符串文件路径,例如/foo/fizzbuzz.bar
,我如何使用bash只提取所述字符串的fizzbuzz
部分?
答案 0 :(得分:489)
以下是如何使用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 manual中找到文档。查找${parameter%word}
和${parameter%%word}
尾随部分匹配部分。
答案 1 :(得分:189)
查看basename命令:
NAME=$(basename /foo/fizzbuzz.bar .bar)
答案 2 :(得分:33)
纯粹的bash,在两个单独的操作中完成:
从路径字符串中删除路径:
path=/foo/bar/bim/baz/file.gif
file=${path##*/}
#$file is now 'file.gif'
从路径字符串中删除扩展名:
base=${file%.*}
#${base} is now 'file'.
答案 3 :(得分:15)
使用basename我使用以下内容来实现此目的:
for file in *; do
ext=${file##*.}
fname=`basename $file $ext`
# Do things with $fname
done;
这不需要文件扩展名的先验知识,即使您的文件名中包含点的文件名(在其前面的扩展名),也不会有效;它确实需要程序basename
,但这是GNU coreutils的一部分,所以它应该附带任何发行版。
答案 4 :(得分:12)
Pure bash方式:
~$ x="/foo/bar/fizzbuzz.bar.quux.zoom";
~$ y=${x/\/*\//};
~$ echo ${y/.*/};
fizzbuzz
在“参数扩展”下的man bash中解释了此功能。非bash方式比比皆是:awk,perl,sed等。
编辑:使用文件后缀中的点,并且不需要知道后缀(扩展名),但不使用中的点名称本身。
答案 5 :(得分:9)
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
答案 6 :(得分:3)
perl -pe 's/\..*$//;s{^.*/}{}'
答案 7 :(得分:3)
使用basename
假设您知道文件扩展名是什么,不是吗?
我相信各种正则表达式建议都不能处理包含多个“。”的文件名。
以下似乎应对双点。哦,以及包含“/”的文件名(仅用于踢)
用Pascal的话来说,“抱歉这个剧本太长了。我没时间把它缩短了”
#!/usr/bin/perl
$fullname = $ARGV[0];
($path,$name) = $fullname =~ /^(.*[^\\]\/)*(.*)$/;
($basename,$extension) = $name =~ /^(.*)(\.[^.]*)$/;
print $basename . "\n";
答案 8 :(得分:3)
如果你不能按照其他帖子的建议使用basename,你可以随时使用sed。这是一个(丑陋的)例子。它不是最好的,但它的工作原理是提取所需的字符串并用想要的字符串替换输入。
echo '/foo/fizzbuzz.bar' | sed 's|.*\/\([^\.]*\)\(\..*\)$|\1|g'
这将为您提供输出
fizzbuzz
答案 9 :(得分:3)
除了POSIX conformant syntax中使用的this answer,
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
引用的文件):< / p>
$ 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*)
答案 10 :(得分:2)
请注意建议的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
如果您知道扩展程序)的解决方案就会简单得多。
答案 11 :(得分:1)
basename执行此操作,删除路径。如果给定它也将删除后缀,如果它与文件的后缀匹配,但您需要知道给命令的后缀。否则你可以使用mv并找出新名称应该是其他方式。
答案 12 :(得分:1)
将排名靠前的答案与排名第二的答案结合起来,获取没有完整路径的文件名:
$ x="/foo/fizzbuzz.bar.quux"
$ y=(`basename ${x%%.*}`)
$ echo $y
fizzbuzz
答案 13 :(得分:0)
你可以使用
mv *<PATTERN>.jar "$(basename *<PATTERN>.jar <PATTERN>.jar).jar"
例如:- 我想从我的文件名中删除 -SNAPSHOT
。对于下面使用的命令
mv *-SNAPSHOT.jar "$(basename *-SNAPSHOT.jar -SNAPSHOT.jar).jar"