string 如何从 Bash 中的路径字符串中删除文件后缀和路径部分?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/125281/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 00:16:58  来源:igfitidea点击:

How do I remove the file suffix and path portion from a path string in Bash?

stringbashfilenames

提问by Lawrence Johnston

Given a string file path such as /foo/fizzbuzz.bar, how would I use bash to extract just the fizzbuzzportion of said string?

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

回答by Zan Lynx

Here's how to do it with the # and % operators in Bash.

下面是如何使用 Bash 中的 # 和 % 运算符来完成它。

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

${x%.bar}could also be ${x%.*}to remove everything after a dot or ${x%%.*}to remove everything after the first dot.

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

Example:

例子:

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

Documentation can be found in the Bash manual. Look for ${parameter%word}and ${parameter%%word}trailing portion matching section.

文档可以在Bash 手册中找到。寻找${parameter%word}${parameter%%word}尾部匹配的部分。

回答by zigdon

look at the basename command:

查看 basename 命令:

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

回答by Param

Pure bash, done in two separate operations:

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

  1. Remove the path from a path-string:

    path=/foo/bar/bim/baz/file.gif
    
    file=${path##*/}  
    #$file is now 'file.gif'
    
  2. Remove the extension from a path-string:

    base=${file%.*}
    #${base} is now 'file'.
    
  1. 从路径字符串中删除路径:

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

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

回答by mike

Using basename I used the following to achieve this:

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

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

    # Do things with $fname
done;

This requires no a priori knowledge of the file extension and works even when you have a filename that has dots in it's filename (in front of it's extension); it does require the program basenamethough, but this is part of the GNU coreutils so it should ship with any distro.

这不需要文件扩展名的先验知识,即使您的文件名中包含点(在其扩展名前面)也可以工作;basename虽然它确实需要该程序,但这是 GNU coreutils 的一部分,因此它应该随任何发行版一起提供。

回答by Vinko Vrsalovic

Pure bash way:

纯bash方式:

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

This functionality is explained on man bash under "Parameter Expansion". Non bash ways abound: awk, perl, sed and so on.

此功能在 man bash 的“参数扩展”下进行了说明。非 bash 方法比比皆是:awk、perl、sed 等。

EDIT: Works with dots in file suffixesand doesn't need to know the suffix (extension), but doesn'twork with dots in the nameitself.

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

回答by Jerub

The basename and dirname functions are what you're after:

basename 和 dirname 函数是您所追求的:

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

Has output:

有输出:

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

回答by Andrew Edgecombe

Using basenameassumes that you know what the file extension is, doesn't it?

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

And I believe that the various regular expression suggestions don't cope with a filename containing more than one "."

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

The following seems to cope with double dots. Oh, and filenames that contain a "/" themselves (just for kicks)

以下似乎处理双点。哦,还有包含“/”的文件名本身(只是为了踢球)

To paraphrase Pascal, "Sorry this script is so long. I didn't have time to make it shorter"

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


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

回答by Benjamin W.

In addition to the POSIX conformant syntaxused in this answer,

除了此答案中使用的符合 POSIX 的语法之外

basename string [suffix]

as in

basename /foo/fizzbuzz.bar .bar

GNU basenamesupports another syntax:

GNUbasename支持另一种语法:

basename -s .bar /foo/fizzbuzz.bar

with the same result. The difference and advantage is that -simplies -a, which supports multiple arguments:

结果相同。不同之处和优点是-s隐含-a,它支持多个参数:

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

This can even be made filename-safe by separating the output with NUL bytes using the -zoption, for example for these files containing blanks, newlines and glob characters (quoted by ls):

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

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

Reading into an array:

读入数组:

$ readarray -d $'
while IFS= read -r -d '' fname; do arr+=("$fname"); done < <(basename -zs .bar has*)
' arr < <(basename -zs .bar has*) $ declare -p arr declare -a arr=([0]=$'has\nnewline' [1]="has space" [2]="has*")

readarray -drequires Bash 4.4 or newer. For older versions, we have to loop:

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

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

回答by nymacro

If you can't use basename as suggested in other posts, you can always use sed. Here is an (ugly) example. It isn't the greatest, but it works by extracting the wanted string and replacing the input with the wanted string.

如果您不能像其他帖子中建议的那样使用 basename,您始终可以使用 sed。这是一个(丑陋的)例子。它不是最大的,但它的工作原理是提取想要的字符串并用想要的字符串替换输入。

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

Which will get you the output

哪个会让你得到输出

fizzbuzz

嘶嘶声

回答by mopoke

##代码##