在bash中提取没有路径和扩展名的文件基名

nev*_*int 303 unix linux bash filenames

给定这样的文件名:

/the/path/foo.txt
bar.txt
Run Code Online (Sandbox Code Playgroud)

我希望得到:

foo
bar
Run Code Online (Sandbox Code Playgroud)

为什么这不起作用?

#!/bin/bash

fullfile=$1
fname=$(basename $fullfile)
fbname=${fname%.*}
echo $fbname
Run Code Online (Sandbox Code Playgroud)

什么是正确的方法呢?

gho*_*g74 594

您不必调用外部basename命令.相反,您可以使用以下命令:

$ s=/the/path/foo.txt
$ echo ${s##*/}
foo.txt
$ s=${s##*/}
$ echo ${s%.txt}
foo
$ echo ${s%.*}
foo
Run Code Online (Sandbox Code Playgroud)

请注意,这个解决方案应该在所有最近的(工作后2004年)POSIX兼容的外壳(例如bash,dash,ksh等).

来源:Shell命令语言2.6.2参数扩展

有关bash String Manipulations的更多信息:http: //tldp.org/LDP/LG/issue18/bash.html

  • 很棒的答案... bash String Manipulations(如`$ {s ##*/}`)在这里解释http://linuxgazette.net/18/bash.html (49认同)
  • @Droogans在经过一番挖掘后发现它:http://www.tldp.org/LDP/LG/issue18/bash.html没有意识到我对此评论有27条赞成:) (25认同)
  • 有没有办法将`##*/`组合在`%.*`(通过嵌套或管道或诸如此类)直接到达foo? (19认同)
  • @chim您是否找到了对链接的更新参考?它死了. (6认同)
  • 文档也可以通过`man -P "less -p 'Parameter Expansion'" bash`获得 (5认同)
  • 在 ubuntu bash 脚本中不起作用,其输出如上所述 (2认同)
  • 这需要解释每个步骤的作用,否则这个答案很难应用于其他解决方案! (2认同)

Mic*_*yan 271

基名命令有两种不同调用; 在一个中,您只指定路径,在这种情况下,它会为您提供最后一个组件,而在另一个中,您还会提供一个将删除的后缀.因此,您可以使用basename的第二次调用来简化示例代码.另外,要小心正确引用事物:

fbname=$(basename "$1" .txt)
echo "$fbname"

  • 有没有办法让它删除任何后缀? (9认同)
  • @handuel 不幸的是,`basename` 不支持通配符。提供第二个参数只会从末尾删除那个确切的文字字符串。 (3认同)
  • 在具有基本名称8.4的计算机上,它的工作原理与本答案中指定的一样,但对于我来说(GNU coreutils的基本名称为8.22),这可以作为`basename -s <extension> <filename>`. (3认同)
  • @w4etwetewtwet - 您可以让 `basename` 删除任何扩展名,请参阅http://stackoverflow.com/a/36341390/2707864 (3认同)

小智 57

basename和cut的组合工作正常,即使在双重结尾的情况下.tar.gz:

fbname=$(basename "$fullfile" | cut -d. -f1)
Run Code Online (Sandbox Code Playgroud)

如果此解决方案比Bash参数扩展需要更少的算术能力,那将会很有趣.

  • 如果文件名称中的其他地方有点,则会错误地截断它。这可能会更好:`fbname=$(basename "$fullfile" | sed -r 's|^(.*?)\.\w+$|\1|')`。更多选择:`'s|^(.*?)\..+$|\1|'`, `'s|^(.*?)\.[^\.]+$|\1|' `. (3认同)
  • 这是我的首选方式 - 使用`$(..)`的小改动 - 所以这变成:`fbname = $(basename"$ fullfile"| cut -d.-f1)` (2认同)

agc*_*agc 19

纯粹bash,不basename,没有变量杂耍.设置一个字符串并echo:

s=/the/path/foo.txt
echo ${s//+(*\/|.*)}
Run Code Online (Sandbox Code Playgroud)

输出:

foo
Run Code Online (Sandbox Code Playgroud)

注意:bash extglob选项必须是"on",(在Ubuntu上它默认为"on"),如果不是,请执行:

shopt -s extglob
Run Code Online (Sandbox Code Playgroud)

走过${s//+(*\/|.*)}:

  1. ${s- 从$ s开始.
  2. // 替换模式的每个实例.
  3. +(匹配一个或更多的的模式列表中括号.
  4. *\/比赛前东西/.(第1种模式)
  5. |要么.(模式分隔符.)
  6. .*匹配之后什么..(第2种模式)
  7. bash结束模式列表.
  8. .结束参数扩展 - 因为没有)(在字符串替换之前),匹配的模式将被删除.

相关}背景:

  1. 模式替换:
  ${parameter/pattern/string}
          Pattern substitution.  The pattern is expanded to produce a pat?
          tern just as in pathname expansion.  Parameter is  expanded  and
          the  longest match of pattern against its value is replaced with
          string.  If pattern begins with /, all matches  of  pattern  are
          replaced   with  string.   Normally  only  the  first  match  is
          replaced.  If pattern begins with #, it must match at the begin?
          ning of the expanded value of parameter.  If pattern begins with
          %, it must match at the end of the expanded value of  parameter.
          If string is null, matches of pattern are deleted and the / fol?
          lowing pattern may be omitted.  If parameter is @ or *, the sub?
          stitution  operation  is applied to each positional parameter in
          turn, and the expansion is the resultant list.  If parameter  is
          an  array  variable  subscripted  with  @ or *, the substitution
          operation is applied to each member of the array  in  turn,  and
          the expansion is the resultant list.
Run Code Online (Sandbox Code Playgroud)
  1. 扩展模式匹配:
  If the extglob shell option is enabled using the shopt builtin, several
   extended  pattern  matching operators are recognized.  In the following
   description, a pattern-list is a list of one or more patterns separated
   by a |.  Composite patterns may be formed using one or more of the fol?
   lowing sub-patterns:

          ?(pattern-list)
                 Matches zero or one occurrence of the given patterns
          *(pattern-list)
                 Matches zero or more occurrences of the given patterns
          +(pattern-list)
                 Matches one or more occurrences of the given patterns
          @(pattern-list)
                 Matches one of the given patterns
          !(pattern-list)
                 Matches anything except one of the given patterns
Run Code Online (Sandbox Code Playgroud)


san*_*ica 16

以下是oneliners:

  1. $(basename ${s%.*})
  2. $(basename ${s} .${s##*.})

我需要这个,就像bongbang和w4etwetewtwet所要求的一样.


hig*_*aro 9

这是获取文件名或扩展名的另一种(更复杂的)方法,首先使用rev命令反转文件路径,从第一个文件切换.,然后再次反转文件路径,如下所示:

filename=`rev <<< "$1" | cut -d"." -f2- | rev`
fileext=`rev <<< "$1" | cut -d"." -f1 | rev`
Run Code Online (Sandbox Code Playgroud)

  • 它们被称为“此处字符串”(更多信息 [此处](http://tldp.org/LDP/abs/html/x17837.html)),基本上它将输入作为字符串并将其提供给您的程序正在阅读标准输入。 (2认同)