如何在 bash 脚本中检查文件名的扩展名?

Posted

技术标签:

【中文标题】如何在 bash 脚本中检查文件名的扩展名?【英文标题】:How to check the extension of a filename in a bash script? 【发布时间】:2010-09-29 06:17:26 【问题描述】:

我正在用 bash 编写一个夜间构建脚本。 一切都很好,除了一点点障碍:


#!/bin/bash

for file in "$PATH_TO_SOMEWHERE"; do
      if [ -d $file ]
      then
              # do something directory-ish
      else
              if [ "$file" == "*.txt" ]       #  this is the snag
              then
                     # do something txt-ish
              fi
      fi
done;

我的问题是确定文件扩展名,然后采取相应措施。我知道问题出在 if 语句中,测试 txt 文件。

如何确定文件是否有 .txt 后缀?

【问题讨论】:

如果您的文件名中有空格,这将中断。 除了Paul的回答,你可以使用$(dirname $PATH_TO_SOMEWHERE)$(basename $PATH_TO_SOMEWHERE)来拆分文件夹和目录,做一些directory-ish和file-ish 【参考方案1】:

制作

if [ "$file" == "*.txt" ]

像这样:

if [[ $file == *.txt ]]

即双括号,不加引号。

== 的右侧是一个 shell 模式。 如果您需要正则表达式,请使用=~

【讨论】:

我不知道这个。 == 或 != 的右侧扩展为 shell 模式似乎是一种特殊情况。我个人认为这比我的答案更清楚。 我是 bash 新手,我花了一些时间才弄清楚如何在多条件 if 语句中使用它。我在这里分享它以防它帮助某人。 if [[ ( $file == *.csv ) || ( $file == *.png ) ]] @cheflo 通常适用于多种情况。在这种特定情况下,您还可以使用if [[ $file =~ .*\.(csv|png) ]]。它更短、更清晰、更容易添加额外的扩展,并且可以很容易地进行配置(通过将“csv|png”放入变量中)。 您可以在文件两边加上双引号。 if [[ "$file" == *.txt ]] 如果文件名中有空格,则需要双引号。 我应该使用这个答案而不是接受的答案吗?【参考方案2】:

我想你想说“$file 的最后四个字符是否等于.txt?”如果是这样,您可以使用以下内容:

if [ "$file: -4" == ".txt" ]

请注意,file:-4 之间的空格是必需的,因为 ':-' 修饰符的含义不同。

【讨论】:

为此,您也可以在 Windows 机器上将 command.com 重命名为 command.txt。 如果要指定不等式,请记住包含额外的括号:if [[ $file: -4 != ".txt" ]] @RamRajamony 为什么在测试不等式时必须使用 [[? 在 bash 中,除非您在第一个变量周围加上引号,否则这将产生“[: ==: unary operator expected”错误。所以改为if [ "$file: -4" == ".txt" ] 对于那些可能不熟悉 bash/shell 语法的人的注意事项:-4 之前的空格很重要。 "$file:-4" == ".txt"(没有空格)将无法按预期工作。【参考方案3】:

在 Unix 系统上,您无法确定 .txt 文件确实是文本文件。你最好的选择是使用“文件”。也许尝试使用:

file -ib "$file"

然后您可以使用 MIME 类型列表来匹配或解析 MIME 的第一部分,您可以在其中获取“文本”、“应用程序”等内容。

【讨论】:

由于file -i...包含mime编码,可以使用file --mime-type -b ...【参考方案4】:

你也可以这样做:

   if [ "$FILE##*." = "txt" ]; then
       # operation for txt files here
   fi

【讨论】:

case $FILE in *.txt ) ... ;; esac 看起来更健壮和惯用。 这将适用于最基本的shell,更通用。 最便携的答案。【参考方案5】:

如果您确实想查找有关文件的信息而不是依赖扩展名,则可以使用“文件”命令。

如果您对使用该扩展感到满意,您可以使用 grep 来查看它是否匹配。

【讨论】:

是的,我知道file 命令。我实际上已经尝试根据所述命令的输出进行匹配......但我在这些 if 语句中失败了。【参考方案6】:

关于如何在linux中获取文件名中可用的扩展名的正确答案是:

$filename##*\. 

打印目录中所有文件扩展名的示例

for fname in $(find . -maxdepth 1 -type f) # only regular file in the current dir
    do  echo $fname##*\. #print extensions 
done

【讨论】:

您的答案使用双反斜杠,但您的示例仅使用单个反斜杠。你的例子是正确的,你的答案不是。【参考方案7】:

类似于“文件”,使用稍微简单一点的“mimetype -b”,无论文件扩展名如何,都可以使用。

if [ $(mimetype -b "$MyFile") == "text/plain" ]
then
  echo "this is a text file"
fi

编辑:如果 mimetype 不可用,您可能需要在系统上安装 libfile-mimeinfo-perl

【讨论】:

您应该明确指出,“mimetype”脚本并非在所有系统上都可用。 完成,添加 libfile-mimeinfo-perl【参考方案8】:

我编写了一个 bash 脚本,它查看文件的类型,然后将其复制到一个位置,我用它来查看我从我的 Firefox 缓存中在线观看的视频:

#!/bin/bash
# flvcache script

CACHE=~/.mozilla/firefox/xxxxxxxx.default/Cache
OUTPUTDIR=~/Videos/flvs
MINFILESIZE=2M

for f in `find $CACHE -size +$MINFILESIZE`
do
    a=$(file $f | cut -f2 -d ' ')
    o=$(basename $f)
    if [ "$a" = "Macromedia" ]
        then
            cp "$f" "$OUTPUTDIR/$o"
    fi
done

nautilus  "$OUTPUTDIR"&

它使用了与此处介绍的类似的想法,希望这对某人有所帮助。

【讨论】:

【参考方案9】:

我猜'$PATH_TO_SOMEWHERE'类似于'<directory>/*'

在这种情况下,我会将代码更改为:

find <directory> -maxdepth 1 -type d -exec ... \;
find <directory> -maxdepth 1 -type f -name "*.txt" -exec ... \;

如果你想对目录和文本文件名做一些更复杂的事情,你可以:

find <directory> -maxdepth 1 -type d | while read dir; do echo $dir; ...; done
find <directory> -maxdepth 1 -type f -name "*.txt" | while read txtfile; do echo $txtfile; ...; done

如果您的文件名中有空格,您可以:

find <directory> -maxdepth 1 -type d | xargs ...
find <directory> -maxdepth 1 -type f -name "*.txt" | xargs ...

【讨论】:

这些是您如何在 shell 中执行“循环”的绝佳示例。显式 forwhile 循环最好保留用于需要更复杂的循环体。

以上是关于如何在 bash 脚本中检查文件名的扩展名?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 bash 脚本更改多个文件的扩展名?

如何在bash中检索文件名或扩展名[重复]

错误 - 在Windows 7中使用“Git Bash Here”时,“文件扩展名.vbs没有脚本引擎”

仅从 Bash 脚本中的路径获取文件名 [重复]

识别 Bash 脚本中文件扩展名的正则表达式模式不准确以捕获压缩文件

在 Bash 中获取文件的扩展名 [重复]