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

问题描述 投票:0回答:11

我正在用 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
后缀?

bash scripting file
11个回答
390
投票

制作

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

像这样:

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

即双括号且不带引号。

==
的右侧是贝壳图案。 如果您需要正则表达式,请使用
=~

用正则表达式:

if [[ $file == =~ \.txt$ ]]

使用此正则表达式,它将接受名称中包含多个点的文件(例如:test.test.txt)。


318
投票

我想你想说“$file 的最后四个字符等于

.txt
吗?” 如果是这样,您可以使用以下方法:

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

请注意,

file:
-4
之间需要有空格,因为 ':-' 修饰符的含义有所不同。


36
投票

你也可以这样做:

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

29
投票

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

file -ib "$file"

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


23
投票

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

如果您觉得使用扩展很舒服,您可以使用 grep 来查看它是否匹配。


17
投票

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

${filename##*\.} 

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

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

12
投票

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

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

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


5
投票

此答案的大部分内容归功于 @Jox,尽管我发现 (js) 与 .json 文件匹配,因此我添加了一个 eol 字符以更完全匹配扩展名。

$file
不需要引用,因为 [[ ]] 不会扩展,因此空格不是问题(来源:Hontvári Levente

if [[ $file =~ .*\.(js$|json$) ]]; then
  echo "The extension of '$file' matches .js|.json";
fi

3
投票

我编写了一个 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"&

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


3
投票

我猜

'$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 ...

0
投票

另一个重要细节,你不要将

else
与另一个
if
一起使用:

else
    if [ "$file" == "*.txt" ]       
    #  this is the snag
    then
    # do something txt-ish
fi

相反:

elif [ "$file" == "*.txt" ]       
    #  this is the snag
then
    # do something txt-ish
fi

else
用于没有任何内容的情况 else left > do > thatcommand

仅仅因为你可以做某事并不一定意味着你应该总是这样做

© www.soinside.com 2019 - 2024. All rights reserved.