给出如下文件名:
/the/path/foo.txt
bar.txt
我希望得到:
foo
bar
为什么这不起作用?
#!/bin/bash
fullfile=$1
fname=$(basename $fullfile)
fbname=${fname%.*}
echo $fbname
这样做的正确方法是什么?
答案 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,(例如bash
,dash
,{{ 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//+(*\/|.*)}
:
${s
- 从 $ s 开始。//
替换该模式的每个实例。+(
在括号中匹配模式列表的一个或多个,( ie 直到下面的第7项)。< / LI>
*\/
匹配字面值之前的任何内容&#34; /
&#34;焦炭。 |
,在此实例中的行为类似于logical OR。.*
匹配文字后的任何内容&#34; .
&#34; - 也就是说,在bash
&#34; .
&#34;只是一个句点字符,而不是 a regex dot。)
结束模式列表。}
结束参数扩展。使用字符串替换时,通常会有另一个/
,后跟一个替换字符串。但由于那里没有/
,匹配的模式被替换为空;这将删除匹配。相关man 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
答案 4 :(得分:13)
以下是oneliners:
$(basename ${s%.*})
$(basename ${s} .${s##*.})
我需要这个,就像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