给定一个字符串文件路径,如/foo/fizzbuzz.bar,我如何使用bash提取只是说字符串的fizzbuzz部分?
/foo/fizzbuzz.bar
fizzbuzz
看看basename命令:
NAME="$(basename /foo/fizzbuzz.bar .bar)"
指示它删除后缀.bar,结果是NAME=fizzbuzz
.bar
NAME=fizzbuzz
纯粹的bash方式:
~$ x="/foo/bar/fizzbuzz.bar.quux.zoom"; ~$ y=${x/\/*\//}; ~$ echo ${y/.*/}; fizzbuzz
这个功能在man bash的“参数扩展”中有解释。非bash方法有很多:awk、perl、sed等等。
编辑:处理文件后缀中的点,不需要知道后缀(扩展名),但不处理文件的名字本身中的点。
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%.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。
${parameter%word}
${parameter%%word}
使用basename假设你知道文件扩展名是什么,不是吗?
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,如果你知道扩展名的话)的解决方案要简单得多。
y=${x%.*}
basename "$x" .ext
使用basename我使用以下方法来实现这一点:
for file in *; do ext=${file##*.} fname=`basename $file $ext` # Do things with $fname done;
这不需要对文件扩展名的先验知识,即使你的文件名中有点(在它的扩展名前面)也可以工作;虽然它确实需要程序basename,但这是GNU coreutils的一部分,所以它应该随任何发行版一起发布。
纯bash,在两个独立的操作中完成:
从路径字符串中删除路径:
path=/foo/bar/bim/baz/file.gif file=${path##*/} #$file is now 'file.gif'
Remove the extension from a path-string:
base=${file%.*} #${base} is now 'file'.
将排名第一的答案与排名第二的答案结合起来,得到没有完整路径的文件名:
$ x="/foo/fizzbuzz.bar.quux" $ y=(`basename ${x%%.*}`) $ echo $y fizzbuzz
除了在这个答案中使用的符合POSIX的语法之外,
basename string [suffix]
as in
basename /foo/fizzbuzz.bar .bar
GNU basename支持另一种语法:
basename -s .bar /foo/fizzbuzz.bar
同样的结果。区别和优势在于-s暗示了-a,它支持多个参数:
-s
-a
$ basename -s .bar /foo/fizzbuzz.bar /baz/foobar.bar fizzbuzz foobar
这甚至可以通过使用-z选项将输出与NUL字节分隔来实现文件名安全,例如对于包含空格、换行符和glob字符(由ls引用)的文件:
-z
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或更新版本。对于旧版本,我们必须循环:
readarray -d
while IFS= read -r -d '' fname; do arr+=("$fname"); done < <(basename -zs .bar has*)
你可以使用
mv *<PATTERN>.jar "$(basename *<PATTERN>.jar <PATTERN>.jar).jar"
例如:-我想从我的文件名中删除-SNAPSHOT。用于下面的命令
-SNAPSHOT
mv *-SNAPSHOT.jar "$(basename *-SNAPSHOT.jar -SNAPSHOT.jar).jar"
如果您想只保留带扩展名的文件名并删除文件路径
$ x="myfile/hello/foo/fizzbuzz.bar" $ echo ${x##*/} $ fizzbuzz.bar
Bash手册中的解释,请参见${parameter##word}
${parameter##word}