假设有以下文件名:
/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
请注意,这个解决方案应该适用于所有近期(2004年以后)的POSIX兼容的shell,比如bash
、dash
、ksh
等。${s##*/}
)的内容,网址为http://linuxgazette.net/18/bash.html。 - chim##*/
和 %.*
结合起来,直接得到 foo? - bongbangman -P "less -p '参数扩展'" bash
获取,该文档将涵盖参数扩展的相关内容。 - Mark Maglanabasename命令有两种不同的用法;其中一种是只指定路径,这时它会返回路径的最后一个组成部分;而另一种用法中您还可以指定要删除的后缀。因此,您可以通过使用basename的第二种用法来简化您的示例代码。此外,请注意正确地引用内容:
fbname=$(basename "$1" .txt) echo "$fbname"
basename
不支持通配符。提供第二个参数只能从末尾删除确切的文字字符串。 - toxalotbasename -s <extension> <filename>
的方式工作。 - Seldom 'Where's Monica' Needybasename
命令移除文件扩展名,请参考https://dev59.com/vnE85IYBdhLWcg3wqleE#36341390。 - sancho.s ReinstateMonicaCelliobasename
在移除扩展名,而是bash
的扩展功能。这与@ghostdog74的解决方案是一样的。使用basename
单独是不可能移除任何扩展名的。 - undefinedfbname=$(basename "$fullfile" | cut -d. -f1)
$(..)
——因此代码如下:fbname=$(basename "$fullfile" | cut -d. -f1)
- FarmerGeddenfbname=$(basename "$fullfile" | sed -r 's|^(.*?)\.\w+$|\1|')
。还有其他选择:'s|^(.*?)\..+$|\1|'
和's|^(.*?)\.[^\.]+$|\1|'
。 - Pysis$(basename "${s%.*}")
$(basename "${s}" ".${s##*.}")
$ s=/the/path/foo.txt
$ echo "$(basename "${s%.*}")"
foo
$ echo "$(basename "${s}" ".${s##*.}")"
foo
纯粹的 bash
,没有 basename
,没有变量操纵。设置一个字符串并使用 echo
命令:
Pure bash
, no basename
, no variable juggling. Set a string and echo
:
p=/the/path/foo.txt
echo "${p//+(*\/|.*)}"
输出:
foo
注意:必须开启 bash
的 extglob 选项(Ubuntu 默认已开启 extglob),否则请执行以下命令:
shopt -s extglob
通过${p//+(*\/|.*)}
步骤:
${p
-- 从$p开始。//
替换所有遵循的模式实例。+(
匹配圆括号中的一个或多个的模式列表,(例如 直到下面的第7项)。*\/
匹配斜杠字符"/
"之前的任何内容。|
在这种情况下充当逻辑或。.*
匹配字面上的".
"之后的任何内容--也就是说,在bash中,".
"只是一个句点字符,而不是正则表达式中的句点。)
结束模式列表。}
结束参数扩展。在字符串替换中,通常会有另一个/
,然后是一个替换字符串。但是由于这里没有/
,因此匹配的模式将被替换为“nothing”,从而删除了匹配项。相关的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
以下是另一种获取文件名或扩展名的较为复杂的方法。首先使用rev
命令来倒转文件路径,然后从第一个.
处进行切割,最后再次倒转文件路径即可,如下:
filename=`rev <<< "$1" | cut -d"." -f2- | rev`
fileext=`rev <<< "$1" | cut -d"." -f1 | rev`
<<<
--这是什么? - Alex Hall如果您想在Cygwin下与Windows文件路径相配合,您也可以尝试以下方法:
fname=${fullfile##*[/|\\]}
我提出了一种替代方法来提取文件扩展名,使用本帖中的帖子和我自己更熟悉的小型知识库。
ext="$(rev <<< "$(cut -f "1" -d "." <<< "$(rev <<< "file.docx")")")"
rev <<< file.docx | cut -f1 -d. | rev
相同的事情,只是没有引号和嵌套子 shell。此外,我认为上述内容根本无法工作。 - matthias krullbasename
,但这不是他的问题。 - chepner
$1
的值确实是您所认为的值,该代码 在大多数情况下 应该能够正常工作。但是,由于引号使用不当,它会受到 单词拆分 和 文件名扩展 的影响。 - toxalot