给出如下文件名:

/the/path/foo.txt
bar.txt

我希望得到:

foo
bar

为什么这行不通?

#!/bin/bash

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

正确的做法是什么?


当前回答

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

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

其他回答

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

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

注意,这个解决方案应该适用于所有最近(2004年以后)的POSIX兼容shell,(例如bash、dash、ksh等)。

2.6.2参数展开

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

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

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

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

basename和cut的组合可以很好地工作,即使是在.tar.gz这样的双结尾的情况下:

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

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

纯bash,没有basename,没有变量杂耍。设置一个字符串并返回:

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

输出:

foo

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

shopt -s extglob

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

${p -- start with $p. // substitute every instance of the pattern that follows. +( match one or more of the pattern list in parenthesis, (i.e. until item #7 below). 1st pattern: *\/ matches anything before a literal "/" char. pattern separator | which in this instance acts like a logical OR. 2nd pattern: .* matches anything after a literal "." -- that is, in bash the "." is just a period char, and not a regex dot. ) end pattern list. } end parameter expansion. With a string substitution, there's usually another / there, followed by a replacement string. But since there's no / there, the matched patterns are substituted with nothing; this deletes the matches.

相关男bash背景:

模式替换:

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

扩展模式匹配:

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

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