在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(例如bash
, dash
, ksh
等)中工作。
源: 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//+(*\/|.*)}
:
-
${s
– 从$ s开始。 -
//
replace模式的每个实例。 -
+(
在括号中匹配一个或多个 模式列表 。 -
*\/
匹配/
之前的任何内容。 (第一种模式) -
|
要么。 (模式分隔符) -
.*
匹配任何东西.
。 (第二模式) -
)
结束模式列表 。 -
}
结束参数扩展 – 因为没有/
(将在一个string替代之前),匹配的模式被删除。
相关的man bash
背景:
- 模式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.
- 扩展模式匹配 :
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`
这里是线索:
-
$(basename ${s%.*})
-
$(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