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

时间:2010-04-19 01:25:29

标签: linux bash unix filenames

给出如下文件名:

/the/path/foo.txt
bar.txt

我希望得到:

foo
bar

为什么这不起作用?

#!/bin/bash

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

这样做的正确方法是什么?

9 个答案:

答案 0 :(得分:559)

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

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

请注意,此解决方案应适用于所有最近的( post 2004 POSIX 兼容的shell,(例如bashdash,{{ 1}}等。)。

来源:Shell Command Language 2.6.2 Parameter Expansion

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

答案 1 :(得分:258)

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

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

答案 2 :(得分:52)

basename和cut的组合工作正常,即使是像.tar.gz那样的双重结尾:

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

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

答案 3 :(得分:16)

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

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

输出:

foo

注意:bash \ textglob 选项必须为" on",( Ubuntu 设置 extglob & #34;默认情况下为#34;如果不是,请执行:

shopt -s extglob

浏览${s//+(*\/|.*)}

  1. ${s - 从 $ s 开始。
  2. //替换该模式的每个实例。
  3. +(在括号中匹配模式列表一个或多个,( ie 直到下面的第7项)。< / LI>
  4. 第一个模式:*\/匹配字面值之前的任何内容&#34; /&#34;焦炭。
  5. 模式分隔符|,在此实例中的行为类似于logical OR
  6. 第二个模式:.*匹配文字后的任何内容&#34; .&#34; - 也就是说,在bash&#34; .&#34;只是一个句点字符,而不是 a regex dot
  7. )结束模式列表
  8. }结束参数扩展。使用字符串替换时,通常会有另一个/,后跟一个替换字符串。但由于那里没有/,匹配的模式被替换为空;这将删除匹配。
  9. 相关man bash背景:

    1. 模式替换
    2.   ${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. 扩展模式匹配
      2.   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
        

答案 4 :(得分:13)

以下是oneliners:

  1. $(basename ${s%.*})
  2. $(basename ${s} .${s##*.})
  3. 我需要这个,就像bongbang和w4etwetewtwet所说的一样。

答案 5 :(得分:9)

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

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

答案 6 :(得分:2)

如果你想玩Windows文件路径(在Cygwin下),你也可以试试这个:

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

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

答案 7 :(得分:0)

我想出了一个提取扩展的替代方法,使用我自己对我更熟悉的小知识库,使用此帖子中的帖子。

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

注意:请告知我使用报价;它对我有用,但我可能会错过正确使用的东西(我可能使用了太多)。

答案 8 :(得分:-10)

使用basename命令。其联机帮助页面位于:http://unixhelp.ed.ac.uk/CGI/man-cgi?basename