【问题标题】:How to check the extension of a filename in a bash script?如何在 bash 脚本中检查文件名的扩展名?
【发布时间】: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

标签: bash scripting file


【解决方案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 循环最好保留用于需要更复杂的循环体。
    猜你喜欢
    • 2021-06-17
    • 1970-01-01
    • 1970-01-01
    • 2013-10-07
    • 2018-12-04
    • 2011-08-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多