我想分别获取文件名(没有扩展名)和扩展名 .
我到目前为止找到的最佳解决方案是:
NAME=`echo "$FILE" | cut -d'.' -f1`
EXTENSION=`echo "$FILE" | cut -d'.' -f2`
这是错误的,因为如果文件名包含多个 .
字符,则它不起作用 . 如果,比方说,我有 a.b.js
,它会考虑 a
和 b.js
,而不是 a.b
和 js
.
它可以在Python中轻松完成
file, ext = os.path.splitext(path)
但是如果可能的话,我宁愿不为此启动Python解释器 .
还有更好的想法?
30 回答
你可以使用basename .
例:
您需要为basename提供应删除的扩展名,但是如果您始终使用
-z
执行tar
,那么您知道扩展名为.tar.gz
.这应该做你想要的:
[从单线程修改为通用bash函数,行为现在与
dirname
和basename
实用程序一致;理由补充说 . ]accepted answer works well in typical cases ,但 fails in edge cases ,即:
对于没有扩展名的文件名(在本答案的其余部分中称为后缀),
extension=${filename##*.}
返回输入文件名而不是空字符串 .与常规相反,
extension=${filename##*.}
不包括初始.
.盲目地预先设置
.
对于没有后缀的文件名不起作用 .filename="${filename%.*}"
将是空字符串,如果输入文件名以.
开头并且不包含其他.
字符(例如,.bash_profile
) - 与惯例相反 .---------
因此, robust solution that covers all edge cases 的复杂性要求 function - 见下面的定义;它 can return all components of a path .
示例电话:
请注意输入路径后面的参数是自由选择的位置变量名称 .
要跳过那些之前不感兴趣的变量,请指定
_
(使用抛弃变量$_
)或''
;例如,要仅提取文件名根目录和扩展名,请使用splitPath '/etc/bash.bashrc' _ _ fnameroot extension
.执行该功能的测试代码:
预期输出 - 注意边缘情况:
没有后缀的文件名
以
.
开头的文件名(不被视为后缀的开头)以
/
结尾的输入路径(尾随/
被忽略)仅作为文件名的输入路径(
.
作为父路径返回)具有多个
.
-prefixed标记的文件名(仅将最后一个标记为后缀):这是代码AWK . 它可以更简单地完成 . 但我对AWK并不擅长 .
好的,如果我理解正确,这里的问题是如何获得具有多个扩展名的文件的名称和完整扩展名,例如
stuff.tar.gz
.这对我有用:
这将为
stuff
提供文件名,.tar.gz
为扩展名 . 它适用于任何数量的扩展,包括0.希望这对任何有相同问题的人都有帮助=)工作正常,所以你可以使用:
顺便说一句,这些命令的工作原理如下 .
NAME
的命令替换"."
字符,后跟任意数量的非"."
字符,直到行的末尾,没有任何内容(即,它删除从最终"."
到行尾的所有内容,包括在内) . 这基本上是使用正则表达式欺骗的非贪婪替换 .EXTENSION
的命令替换任意数量的字符,后跟行尾的"."
字符,没有任何内容(即,它删除从行的开头到最后一个点的所有内容,包括在内) . 这是一个贪婪的替换,这是默认操作 .一个简单的答案:
要扩展POSIX variables answer,请注意您可以执行更多有趣的模式 . 因此,对于此处详述的案例,您可以简单地执行此操作:
这将切断.tar . <something>的最后一次出现 .
更一般地说,如果你想删除最后一次出现 . <something> . <something-else>那么
应该工作正常 .
上述答案的链接似乎已经死了 . Here's a great explanation of a bunch of the string manipulation you can do directly in Bash, from TLDP .
我使用以下脚本
梅伦在博客文章评论中写道:
使用Bash,还有
${file%.*}
来获取没有扩展名的文件名和${file##*.}
来单独获取扩展名 . 那是,输出:
魔术文件识别
除了这个Stack Overflow问题的很多好答案之外,我想补充一下:
在Linux和其他unixen下,有一个名为
file
的魔术命令,它通过分析文件的第一个字节来进行文件类型检测 . 这是一个非常古老的工具,最初用于打印服务器(如果没有创建...我不确定) .标准扩展可以在
/etc/mime.types
中找到(在我的Debian GNU / Linux桌面上 . 请参阅man file
和man mime.types
. 也许您必须安装file
实用程序和mime-support
包):您可以创建一个bash函数来确定正确的扩展名 . 有一点(不完美)的样本:
此函数可以设置一个可以在以后使用的Bash变量:
(这是受@Petesh正确答案的启发):
对于这个简单的任务,无需为
awk
或sed
甚至perl
而烦恼 . 有一个纯Bash,os.path.splitext()
兼容的解决方案,它只使用参数扩展 .参考实施
os.path.splitext(path)的文档:
Python代码:
Bash实施
尊重领先期
忽略领先期
测试
以下是Ignoring leading period实现的测试用例,它应该与每个输入上的Python参考实现相匹配 .
测试结果
所有测试都通过了
如何在fish中提取文件名和扩展名:
Caveats: 最后一个点上的拆分,适用于带有点的文件名,但不适用于包含点的扩展名 . 见下面的例子 .
Usage:
可能有更好的方法来做到这一点 . 随意编辑我的答案以改进它 .
如果有一组有限的扩展你将要处理,你知道所有这些扩展,试试这个:
这确实是 not 作为第一个例子,但是您必须处理每个案例,因此根据您可以预期的扩展数量,它可能会更加繁琐 .
最小和最简单的解决方案(单线)是:
如果文件没有扩展名或没有文件名,那似乎不起作用 . 这是我正在使用的;它只使用内置函数并处理更多(但不是全部)病态文件名 .
以下是一些测试用例:
您可以强制剪切以显示将
-
添加到字段编号的所有字段和后续字段 .所以如果FILE是
eth0.pcap.gz
,EXTENSION将是pcap.gz
使用相同的逻辑,您还可以使用带有cut的' - '来获取文件名,如下所示:
这适用于没有任何文件名的文件名延期 .
通常您已经知道扩展名,因此您可能希望使用:
例如:
我们得到了
以下是一些替代建议(主要在
awk
中),包括一些高级用例,例如提取软件包的版本号 .所有用例都使用原始完整路径作为输入,而不依赖于中间结果 .
从上面的答案,最短的oneliner模仿Python的
假设您的文件确实有扩展名,是
您可以使用cut命令删除最后两个扩展名(
".tar.gz"
部分):正如Clayton Hughes在评论中指出的那样,这对问题中的实际例子不起作用 . 所以作为一种替代方案,我建议使用带有扩展正则表达式的
sed
,如下所示:它的工作原理是无条件地删除最后两个(字母数字)扩展 .
[在Anders Lindahl发表评论后再次更新]
这适用于文件名中的多个点和空格,但是如果没有扩展名,则返回文件名本身 . 虽然容易检查;只测试文件名和扩展名是一样的 .
当然,这种方法不适用于.tar.gz文件 . 但是,这可以通过两个步骤处理 . 如果扩展名为gz,则再次检查以查看是否还有tar扩展名 .
为了使dir更有用(在没有路径的本地文件被指定为输入的情况下),我执行了以下操作:
这允许您执行一些有用的操作,例如为输入文件basename添加后缀:
我想如果你只需要文件的名称,你可以试试这个:
这就是全部= D.
如果您还想允许 empty 扩展,这是我能想到的最短时间:
第一行解释:它匹配PATH.EXT或ANYTHING并用EXT替换它 . 如果ANYTHING匹配,则不捕获ext组 .
你可以使用POSIX变量的神奇之处:
有一点需要注意,如果您的文件名是
./somefile.tar.gz
形式,那么echo ${FILENAME%%.*}
会贪婪地删除与.
的最长匹配,并且您将拥有空字符串 .(您可以使用临时变量解决此问题:
)
这site解释得更多 .
这是我用来查找文件的名称和扩展名的算法,当我编写一个Bash脚本,以便在名称与套管冲突时使名称唯一 .
试运行 .
仅供参考:完整的音译程序和更多测试用例可在此处找到:https://www.dropbox.com/s/4c6m0f2e28a1vxf/avoid-clashes-code.zip?dl=0
首先,获取没有路径的文件名:
或者,您可以专注于路径的最后一个'/'而不是' . '即使你有不可预测的文件扩展名,它应该工作:
您可能需要查看文档:
在网页“3.5.3 Shell Parameter Expansion”部分
在名为"Parameter Expansion"的部分的bash联机帮助页中
从Petesh回答构建,如果只需要文件名,则可以在一行中删除路径和扩展名,
有关更多详细信息,请参阅Bash手册中的shell parameter expansion .
只需使用
${parameter%word}
在你的情况下:
如果您想测试它,以下所有工作,只需删除扩展名:
很大程度上取决于@ mklement0的优秀,充满了随机,有用的基本原理 - 以及对此/其他问题的其他答案/ "that darn internet" ...我把它全部包含在我的一点点,更易于理解,可重复使用的功能中(或者你的)
.bash_profile
负责什么(我考虑)应该是dirname
/basename
/你有什么更强大的版本..用法示例......
您可以使用
获取文件名和
得到扩展 .
测试用例: