【问题标题】:Extract file basename without path and extension in bash [duplicate]在bash中提取没有路径和扩展名的文件基名[重复]
【发布时间】:2011-02-09 12:29:42
【问题描述】:

给定这样的文件名:

/the/path/foo.txt
bar.txt

我希望得到:

foo
bar

为什么这不起作用?

#!/bin/bash

fullfile=$1
fname=$(basename $fullfile)
fbname=${fname%.*}
echo $fbname

正确的做法是什么?

【问题讨论】:

  • 只要$1 的值实际上是您认为的值,此代码在大多数情况下应该可以工作。但因quoting不当,以word splittingfilename expansion为准。
  • 更接近 @tripleee:这不是 Extract filename and extension in Bash 的副本。另一个更复杂的 Q 要求扩展名和文件名分开。如果有的话,另一个问题是对这个更基本的问题的阐述。
  • @agc 答案似乎非常相似,但旧问题的答案更多。你能解释一下为什么你认为这些应该分开吗?
  • @tripleee 对更简单问题感兴趣的用户可能会被添加或解决更复杂问题所需的不同代码不必要地混淆。
  • 您阅读其他问题的答案了吗?在前五名中,有四名非常清楚地展示了如何做到这一点,并解释了选项,其中大多数都非常简洁。如果您能指出实际差异,我很高兴被说服,但我没有看到它们。或许可以在 Meta Stack Overflow 上提出这个问题,以获得更广泛的知名度。

标签: linux bash unix filenames


【解决方案1】:

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

$ s=/the/path/foo.txt
$ echo "${s##*/}"
foo.txt
$ s=${s##*/}
$ echo "${s%.txt}"
foo
$ echo "${s%.*}"
foo

请注意,此解决方案应适用于所有最近(2004 年后POSIX 兼容的 shell,(例如 bashdashksh 等。 )。

来源:Shell Command Language 2.6.2 Parameter Expansion

更多关于 bash 字符串操作的信息:http://tldp.org/LDP/LG/issue18/bash.html

【讨论】:

  • 绝妙的答案... bash 字符串操作(如 ${s##*/} )在此处解释 linuxgazette.net/18/bash.html
  • @chim 您是否找到了对您的链接的更新参考?它已经死了。
  • @Droogans 经过一番挖掘后找到了它 :) tldp.org/LDP/LG/issue18/bash.html 没有意识到我对此评论有 27 个赞成票 :)
  • 有没有办法将##*/%.* 结合起来(通过嵌套或管道等)直接到达foo?
  • 文档也可以通过man -P "less -p 'Parameter Expansion'" bash获得
【解决方案2】:

basename 命令有两个不同的调用;在一个中,您只指定路径,在这种情况下,它为您提供最后一个组件,而在另一个中,您还提供一个将删除的后缀。因此,您可以通过使用 basename 的第二次调用来简化示例代码。另外,请注意正确引用内容:

fbname=$(basename "$1" .txt) 回声“$ fbname”

【讨论】:

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

使用 basename 命令。它的手册页在这里:http://unixhelp.ed.ac.uk/CGI/man-cgi?basename

【讨论】:

  • 他正在使用basename,但这不是他的问题。
【解决方案4】:

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

filename=`rev <<< "$1" | cut -d"." -f2- | rev`
fileext=`rev <<< "$1" | cut -d"." -f1 | rev`

【讨论】:

  • 我从未见过那些三重尖括号&lt;&lt;&lt; doohickeys——那是什么?
  • 它们被称为“Here Strings”(更多信息here),基本上它将输入作为字符串并在通过标准输入读取时将其提供给您的程序。
【解决方案5】:

如果你想很好地使用 Windows 文件路径(在 Cygwin 下),你也可以试试这个:

fname=${fullfile##*[/|\\]}

这将在 Windows 上使用 BaSH 时考虑反斜杠分隔符。

【讨论】:

    【解决方案6】:

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

    fbname=$(basename "$fullfile" | cut -d. -f1)
    

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

    【讨论】:

    • 这是我的首选方式 - 使用 $(..) 的细微变化 - 所以变成:fbname=$(basename "$fullfile" | cut -d. -f1)
    • 这是一个很好的解决方案,因为它会截断 all(点)扩展。
    • 如果文件名称中的其他地方有点,这会错误地截断它。这可能会更好:fbname=$(basename "$fullfile" | sed -r 's|^(.*?)\.\w+$|\1|')。更多选择::'s|^(.*?)\..+$|\1|''s|^(.*?)\.[^\.]+$|\1|'
    【解决方案7】:

    只是我想出的另一种方法来提取扩展,使用这个线程中的帖子和我自己更熟悉的小型知识库。

    ext="$(rev <<< "$(cut -f "1" -d "." <<< "$(rev <<< "file.docx")")")"
    

    注意:请告知我对引号的使用;它对我有用,但我可能在正确使用它们时遗漏了一些东西(我可能使用了太多)。

    【讨论】:

    • 你不需要单引号,你尝试做同样的事情:rev &lt;&lt;&lt; file.docx | cut -f1 -d. | rev 只是没有引号和没有嵌套的子外壳。另外我认为上述方法根本行不通。
    【解决方案8】:

    这里是单线:

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

    我需要这个,正如 bongbang 和 w4etwetewtwet 所要求的。

    【讨论】:

      【解决方案9】:

      bash,没有basename,没有变量杂耍。设置一个字符串和echo:

      p=/the/path/foo.txt
      echo "${p//+(*\/|.*)}"
      

      输出:

      foo
      

      注意:bash extglob 选项必须为“on”,(Ubuntu 默认将 extglob 设置为“on”),如果不是,做:

      shopt -s extglob
      

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

      1. ${p -- 以 $p 开头。
      2. // 替换后面模式的每个实例。
      3. +( 匹配 一个或多个 括号中的模式列表,(直到下面的第 7 项)。
      4. 1st 模式:*\/ 匹配文字“/”字符之前的任何内容。
      5. 模式分隔符|,在这种情况下类似于logical OR
      6. 2nd 模式:.* 匹配文字“.”之后的任何内容——也就是说,在bash 中,“.”只是一个句点字符,而 不是 a regex dot.
      7. ) 结束模式列表
      8. }结束参数扩展。使用字符串替换时,通常会有另一个/,然后是替换字符串。但由于那里没有/,匹配的模式被替换为空;这会删除匹配项。

      相关man bash背景:

      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.
      
      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
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-09-21
        • 2012-10-11
        • 1970-01-01
        • 2011-12-08
        相关资源
        最近更新 更多