本问题已经有最佳答案,请猛点这里访问。
给定的文件名如下:
/the/path/foo.txt
bar.txt
我希望得到:
foo
bar
为什么这样不行?
#!/bin/bash
fullfile=$1
fname=$(basename $fullfile)
fbname=${fname%.*}
echo $fbname
正确的方法是什么?
只要EDOCX1的值(0)实际上是您所认为的值,那么在大多数情况下,该代码都可以工作。但是,由于引用不当,会导致分词和扩展文件名。
您不必调用外部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等)。
来源:shell命令语言2.6.2参数扩展
关于bash字符串操作的更多信息:http://tldp.org/ldp/lg/issue18/bash.html
完美的答案…这里解释了bash字符串操作(如${s##*/})linuxgazette.net/18/bash.html
@你找到链接的更新参考了吗?它死了。
@Droogans是在挖掘之后发现的:)t ldp.org/ldp/lg/issue18/bash.html没有意识到我对这个评论有27个赞成票:)
非常方便,用于文件扩展和选择。示例:options=~/path/user.*,然后是select result in ${options[@]##*/};。
有没有办法将##*/与%.*结合起来(通过嵌套或管道或其他方式)直接到达foo?
顺便说一句,TLDP的文档没有很好地维护;wiki.bash-hacker.org/syntax/pe和mywiki.wooledge.org/bashfaq/100可能是更好的参考。
@bongbang,不;bash不允许嵌套pes。(zsh有,但在这方面几乎是孤独的)。
在输出如前所述的Ubuntu bash脚本中不工作
@Bongbang-你可以把所有东西都放在一行中,在这篇文章中稍加修改,请参见stackoverflow.com/a/36341390/2707864。
Linux Gazette链接现在已断开:lg 18现在可通过tldp.org/ldp/lg/issue18/bash.html获得。
仅供参考,也在zsh上工作。
文件也可通过man -P"less -p 'Parameter Expansion'" bash获得。
@Chim上述链接已断开。这里是存档版本web beta.archive.org/web/20111026140412/http://hellip;
你怎么在fish里做这个?
如果我的路径类似于user/my_folder/[this_is_my_file]*,会发生什么?当我遵循这些步骤时,我得到的是[this_is_my_file]*。
basename命令有两种不同的调用;一种是只指定路径,在这种情况下,它会给出最后一个组件,而在另一种情况下,它还会给出一个将要删除的后缀。因此,您可以使用第二次调用basename来简化示例代码。此外,请注意正确引用以下内容:
fbname=$(basename"$1" .txt)
echo"$fbname"
有没有办法让它去掉任何后缀?
@不幸的是,basename不支持通配符。提供第二个参数只会从结尾处删除该确切的文本字符串。
在basename为8.4的机器上,它的工作方式与此答案中指定的一样,但对于我(从GNU coreutils获得basename为8.22)来说,它的工作方式是basename -s。
@w4etwetewtwet-您可以让basename删除任何扩展名,请参阅stackoverflow.com/a/36341390/2707864
basename和cut的组合效果很好,即使是像.tar.gz这样的双端:
fbname=$(basename"$fullfile" | cut -d. -f1)
如果这个解决方案比bash参数扩展需要更少的算术能力,那就很有趣了。
这是我的首选方式——使用$(..)的微小变化——所以这变成了:fbname=$(basename"$fullfile" | cut -d. -f1)。
这是一个很好的解决方案,因为它将截取所有(点)扩展。
如果文件名中的其他地方有点,则会错误地截断它。这可能会更好:fbname=$(basename"$fullfile" | sed -r 's|^(.*?)\.\w+$|\1|')。更多选择:'s|^(.*?)\..+$|\1|'、's|^(.*?)\.[^\.]+$|\1|'。
纯bash,无basename,无变戏法。设置字符串和echo:
s=/the/path/foo.txt
echo ${s//+(*\/|.*)}
输出:
foo
注:bashextglob选项必须为"on"(在Ubuntu上默认为"on"),否则,请执行以下操作:
shopt -s extglob
走过${s//+(*\/|.*)}:
${s--从$s开始。
//替代了模式的每个实例。
+(匹配括号中的一个或多个模式列表。
*\/匹配/之前的任何内容。(第一种模式)
|或。(模式分隔符。)
.*匹配.之后的任何内容。(第二种模式)
)端模式列表。
}结束参数扩展——由于没有/(在字符串替换之前),匹配的模式将被删除。
相关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
以下是一句话:
$(basename ${s%.*})
$(basename ${s} .${s##*.})
我需要这个,就像邦邦和W4etwetwet要求的那样。
以下是获取文件名或扩展名的另一种(更复杂)方法,首先使用rev命令反转文件路径,从第一个.中剪切,然后再次反转文件路径,如下所示:
filename=`rev <<
fileext=`rev <<
我从来没有见过那些三角支架<<
它们被称为"这里的字符串"(这里有更多信息),基本上它把输入作为一个字符串,并在程序读取stdin时将其馈送给程序。
如果您想使用Windows文件路径(在cygwin下)进行良好的播放,也可以尝试以下操作:
fname=${fullfile##*[/|\\]}
在Windows上使用bash时,这将解释反斜杠分隔符。
只是我想出的一个替代方法来提取一个扩展,使用这个线程中的文章和我自己更熟悉的小知识库。
ext="$(rev <<
注意:请建议我使用报价单;它对我有效,但我可能会错过一些关于它们正确使用的内容(我可能使用太多)。
您不需要一个单引号,您尝试这样做:rev <<< file.docx | cut -f1 -d. | rev,只是不带引号,也不带嵌套的子shell。另外,我认为上述方法根本行不通。
使用basename命令。它的主页在这里:http://unixhelp.ed.ac.uk/cgi/man-cgi?基名
他用的是basename,但这不是他的问题。