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

Posted

技术标签:

【中文标题】识别 Bash 脚本中文件扩展名的正则表达式模式不准确以捕获压缩文件【英文标题】:Regex pattern that recognises file extension in Bash script not accurate to capture compressed files 【发布时间】:2019-01-08 15:08:07 【问题描述】:

我创建了这个有一个参数(文件名)的小 Bash 脚本,该脚本应该根据文件的扩展名做出响应:

#!/bin/bash

fileFormat=$1

if [[ $fileFormat =~ [Ff][Aa]?[Ss]?[Tt]?[Qq]\.?[[:alnum:]]+$ ]]; then
    echo "its a FASTQ file";
elif [[ $fileFormat =~ [Ss][Aa][Mm] ]]; then
    echo "its a SAM file";
else
    echo "its not fasta nor sam";
fi

它是这样运行的:

sh script.sh filename.sam

如果它是一个 fastq(或 FASTQ、或 fq、或 FQ 或 fastq.gz(压缩)),我希望脚本告诉我“它是一个 fastq”。如果是 sam,我想让它告诉我它是 sam,如果不是,我想告诉我它既不是 sam 也不是 fastq。

问题:当我没有考虑 .gz(压缩)场景时,脚本运行良好并给出了我预期的结果,但是当我尝试添加最后一部分时发生了一些事情考虑这种情况(见第三行,它说的部分 .?[[:alnum:]]+ )。这部分的意思是“在文件名中,在扩展名之后(在这种情况下为fastq),后面可能有一个点加上一些单词”。

我的输入是这样的:

sh script.sh filename.fastq.gz

而且它有效。但如果我说: sh script.sh 文件名.fastq

它说它不是 fastq。我想把最后一部分作为可选的,但如果我添加一个“?”最后它不起作用。有什么想法吗?谢谢! 我的问题是修复该部分以适用于这两种情况。

【问题讨论】:

抱歉,我刚刚编辑了问题。现在你可以看到它了 尝试将\.?[[:alnum:]]+更改为(?:\.[[:alnum:]]+)? 抱歉,请参阅新的编辑。很抱歉给您带来不便,我在完成帖子之前不小心提交了问题,之后我不得不通过编辑完成它。 file(1)而不是名字怎么样? 使用shopt -s nocasematch 进行不区分大小写的正则表达式匹配,而不是使用[Ff] 【参考方案1】:

你可以使用这个正则表达式:

fileFormat="$1"

if [[ $fileFormat =~ [Ff]([Aa][Ss][Tt])?[Qq](\.[[:alnum:]]+)?$ ]]; then
    echo "its a FASTQ file"
elif [[ $fileFormat =~ [Ss][Aa][Mm]$ ]]; then
    echo "its a SAM file"
else
    echo "its not fasta nor sam"
fi

这里(\.[[:alnum:]]+)? 使最后一组可选,即点后跟1+ 字母数字字符。

当你运行它时:

./script.sh filename.fastq
its a FASTQ file

./script.sh fq
its a FASTQ file

./script.sh filename.fastq.gz
its a FASTQ file

./script.sh filename.sam
its a SAM file

./script.sh filename.txt
its not fasta nor sam

【讨论】:

这就是我一直在寻找的(因为它解决了我的代码的特定问题)。非常感谢 !! :) 这仍然会在文件名中的任何位置查找“sam”,不是吗?所以“samba.txt”会匹配。 如果你把 $ 放在最后 ([Ss][Aa][Mm]$) 它适用于 sam 后跟单词结尾的情况(因此不考虑以下情况它在文件名的中间) 既然是“fastq”或“fq”,不应该是[Ff]([Aa][Ss][Tt])?[Qq]吗? 非常有效的点@BenjaminW.,否则它会将filename.ftq 也标记为FASTQ 文件。现已编辑,谢谢。【参考方案2】:

直接的问题是您需要在.fastq 之后至少有一个[[:alnum:]] 字符。使用* 而不是+,这本身很容易解决。

不过,对于这个问题,Regex 并不是一个特别令人满意的解决方案。

case $fileFormat in
    *.[Ff][Aa][Ss][Tt][Qq] | *.[Ff][Aa][Ss][Tt][Qq].*)
        echo "$0: $fileFormat is a FASTQ file" >&2 ;;
    *.[Ss][Aa][Mm] )
        echo "$0: $fileFormat is a SAM file" >%2 ;;
esac

可一直移植到原始 Bourne sh。在 Bash 4.x 中,您可以在比较之前将文件名小写,以简化 glob 模式。

还要注意诊断如何包含脚本名称并打印到标准错误而不是标准输出。

【讨论】:

不错的便携想法,但 OP 也需要匹配 .FQ.fq,不是吗? 是的,但这也适用于 .FQ 和 .fq。我喜欢它,但它也会识别文件名的某些部分中的 fastq,而不一定是单词的最后一个位置。这就是为什么我试图使用另一种方式(也将 $ 放在最后和其他东西上,而不是让它捕捉接下来发生的任何事情)。但是对于这个简单的脚本来说是一个不错的解决方案

以上是关于识别 Bash 脚本中文件扩展名的正则表达式模式不准确以捕获压缩文件的主要内容,如果未能解决你的问题,请参考以下文章

bash 中的正则表达式量词——简单与扩展匹配 n 次

Bash之正则表达式

Bash 正则表达式重命名文件

Linux 第17天 bash,find,正则,命令历史

linux学习第4天(自习)

Bash 脚本:正则表达式基础篇 | Linux 中国