给定一个字符串文件路径,例如 /foo/fizzbuzz.bar ,我如何使用bash只提取所述字符串的 fizzbuzz 部分?

有帮助吗?

解决方案

以下是如何使用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} 尾随部分匹配部分。

其他提示

查看basename命令:

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

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

  1. 从路径字符串中删除路径:

    path=/foo/bar/bim/baz/file.gif
    
    file=${path##*/}  
    #$file is now 'file.gif'
    
  2. 从路径字符串中删除扩展名:

    base=${file%.*}
    #${base} is now 'file'.
    

使用basename我使用以下命令来实现此目的:

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

    # Do things with $fname
done;

这不需要文件扩展名的先验知识,即使你的文件名在其文件名中有点(在它的扩展名前面),也不会有效;它确实需要程序 basename ,但这是GNU coreutils的一部分,所以它应该附带任何发行版。

Pure bash方式:

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

此功能在“参数扩展”下的man bash中进行了解释。非bash方式比比皆是:awk,perl,sed等。

编辑:使用文件后缀中的点,并且不需要知道后缀(扩展名),但不会使用<中的点< em> name 本身。

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
perl -pe 's/\..*$//;s{^.*/}{}'

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

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

以下似乎应对双点。哦,以及包含“/”的文件名。他们自己(只是为了踢)

用Pascal来解释,“抱歉这个脚本太长了。我没有时间把它缩短“


  #!/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'

这将为您提供输出

  
    

fizzbuzz

  

POSIX符合语法之外href =“https://stackoverflow.com/a/125287/3266847”>这个答案,

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'

读入数组:

$ readarray -d 

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

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

读入数组:

<*>

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

<*>\0' arr < <(basename -zs .bar has*) $ declare -p arr declare -a arr=([0]=

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

<*>\n''newline.bar' 'has space.bar' 'has*.bar'

读入数组:

<*>

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

<*>has\nnewline' [1]="has space" [2]="has*")

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

<*>\n''newline.bar' 'has space.bar' 'has*.bar'

读入数组:

<*>

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

<*>

请注意建议的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&quot; $ x&quot; .ext ,如果你知道的话扩展)更简单。

basename执行此操作,删除路径。如果给定它也将删除后缀,如果它与文件的后缀匹配,但您需要知道给命令的后缀。否则你可以使用mv并找出新名称应该是其他方式。

将排名靠前的答案与排名第二的答案结合起来,获取没有完整路径的文件名:

$ x="/foo/fizzbuzz.bar.quux"
$ y=(`basename ${x%%.*}`)
$ echo $y
fizzbuzz
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top