在bash中提取没有path和扩展名的文件基本名称

鉴于这样的文件名称:

/the/path/foo.txt bar.txt 

我希望得到:

 foo bar 

为什么这不起作用?

 #!/bin/bash fullfile=$1 fname=$(basename $fullfile) fbname=${fname%.*} echo $fbname 

什么是正确的方法来做到这一点?

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

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

请注意,这个解决scheme应该可以在所有最近的( 2004年以后 )兼容POSIX的 shell(例如bashdashksh等)中工作。

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

更多关于bash的string操作: http : //tldp.org/LDP/LG/issue18/bash.html

basename命令有两个不同的调用; 在一个,你指定的path,在这种情况下,它给你最后一个组件,而在另一个你也给一个后缀,它将被删除。 所以,你可以使用第二次调用基本名称来简化你的示例代码。 另外,要小心地正确引用的东西:

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

基本名称和剪切的组合工作正常,即使在双重结局如.tar.gz情况下:

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

如果这个解决scheme比Bash参数扩展需要更less的算术能力,这将是有趣的。

纯粹的bash ,没有basename ,没有变数的杂耍。 设置一个string和echo

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

输出:

 foo 

注意: bash extglob选项必须是“on”(在Ubuntu上默认为“on”),如果不是这样的话:

 shopt -s extglob 

遍历${s//+(*\/|.*)}

  1. ${s – 从$ s开始。
  2. //replace模式的每个实例。
  3. +(在括号中匹配一个或多个 模式列表
  4. *\/匹配/之前的任何内容。 (第一种模式)
  5. | 要么。 (模式分隔符)
  6. .*匹配任何东西. 。 (第二模式)
  7. )结束模式列表
  8. }结束参数扩展 – 因为没有/ (将在一个string替代之前),匹配的模式被删除。

相关的man bash背景:

  1. 模式replace
  ${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 

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

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

这里是线索:

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

我需要这个,就像bongbang和w4etwetewtwet一样。

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

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

在Windows上使用BaSH时,这将占用反斜线分隔符。

只是一个替代scheme,我提出了一个扩展,使用在这个线程中的职位,我自己的小知识基础,这是我更熟悉。

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

注意:请告诉我使用报价; 它为我工作,但我可能会错过一些正确的使用(我可能使用太多)。

使用basename命令。 其手册页是: http : //unixhelp.ed.ac.uk/CGI/man-cgi?basename