【发布时间】:2010-09-12 14:55:41
【问题描述】:
给定一个字符串文件路径,例如/foo/fizzbuzz.bar,我将如何使用 bash 仅提取所述字符串的 fizzbuzz 部分?
【问题讨论】:
-
您可以在Bash manual 中找到的信息,在尾部匹配部分查找
${parameter%word}和${parameter%%word}。
给定一个字符串文件路径,例如/foo/fizzbuzz.bar,我将如何使用 bash 仅提取所述字符串的 fizzbuzz 部分?
【问题讨论】:
${parameter%word} 和${parameter%%word}。
你可以使用
mv *<PATTERN>.jar "$(basename *<PATTERN>.jar <PATTERN>.jar).jar"
例如:- 我想从我的文件名中删除 -SNAPSHOT。对于下面使用的命令
mv *-SNAPSHOT.jar "$(basename *-SNAPSHOT.jar -SNAPSHOT.jar).jar"
【讨论】:
查看basename命令:
NAME="$(basename /foo/fizzbuzz.bar .bar)"
指示它删除后缀.bar,结果为NAME=fizzbuzz
【讨论】:
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
【讨论】:
mystring=$1 运行这个而不是当前的常量值(这将抑制几个警告,确保不包含空格/ glob 字符/等),并解决它发现的问题?
echo "basename: $(basename "$mystring")" - 如果mystring='/foo/*' 你没有将* 替换为当前目录中的文件列表 在 basename 完成之后。
除了this answer中使用的POSIX conformant syntax,
basename <i>string</i> [<i>suffix</i>]
如
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 字节分隔开来实现文件名安全,例如对于这些包含空格、换行符和全局字符的文件(由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*)
【讨论】:
下面是如何在 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} 尾随部分匹配部分。
【讨论】:
纯 bash,在两个单独的操作中完成:
从路径字符串中删除路径:
path=/foo/bar/bim/baz/file.gif
file=${path##*/}
#$file is now 'file.gif'
从路径字符串中删除扩展名:
base=${file%.*}
#${base} is now 'file'.
【讨论】:
将评分最高的答案与第二名的答案结合起来,得到没有完整路径的文件名:
$ x="/foo/fizzbuzz.bar.quux"
$ y=(`basename ${x%%.*}`)
$ echo $y
fizzbuzz
【讨论】:
使用 basename 我使用以下方法来实现:
for file in *; do
ext=${file##*.}
fname=`basename $file $ext`
# Do things with $fname
done;
这不需要文件扩展名的先验知识,即使您的文件名在其文件名中包含点(在其扩展名前面)也可以工作;虽然它确实需要程序 basename,但这是 GNU coreutils 的一部分,因此它应该随任何发行版一起提供。
【讨论】:
fname=`basename $file .$ext`
$file、$ext 和反引号部分(包括反引号本身)用双引号括起来。
纯 bash 方式:
~$ x="/foo/bar/fizzbuzz.bar.quux.zoom";
~$ y=${x/\/*\//};
~$ echo ${y/.*/};
fizzbuzz
此功能在 man bash 中的“参数扩展”下进行了说明。非 bash 方式比比皆是:awk、perl、sed 等等。
编辑:使用文件后缀中的点并且不需要知道后缀(扩展名),但不使用中的点自己命名。
【讨论】:
注意建议的 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,如果您知道扩展名)的解决方案要简单得多。
【讨论】:
基本名称会这样做,删除路径。如果给定后缀,并且它与文件的后缀匹配,它也会删除后缀,但您需要知道给命令提供的后缀。否则,您可以使用 mv 并以其他方式找出新名称应该是什么。
【讨论】:
如果您不能按照其他帖子中的建议使用 basename,则始终可以使用 sed。这是一个(丑陋的)例子。它不是最好的,但它通过提取想要的字符串并将输入替换为想要的字符串来工作。
echo '/foo/fizzbuzz.bar' | sed 's|.*\/\([^\.]*\)\(\..*\)$|\1|g'
这将为您提供输出
嘶嘶声
【讨论】:
使用basename 假设您知道文件扩展名是什么,不是吗?
而且我相信各种正则表达式建议无法处理包含多个“。”的文件名
以下似乎可以处理双点。哦,还有包含“/”的文件名(只是为了好玩)
套用 Pascal 的话说,“抱歉,这个脚本太长了。我没有时间把它缩短”
#!/usr/bin/perl
$fullname = $ARGV[0];
($path,$name) = $fullname =~ /^(.*[^\\]\/)*(.*)$/;
($basename,$extension) = $name =~ /^(.*)(\.[^.]*)$/;
print $basename . "\n";
【讨论】:
perl -pe 's/\..*$//;s{^.*/}{}'
【讨论】: