获取文件名中的扩展名

ura*_*ray 43 shell bash filenames

如何从 bash 获取文件扩展名?这是我尝试过的:

filename=`basename $filepath`
fileext=${filename##*.}
Run Code Online (Sandbox Code Playgroud)

通过这样做,我可以bz2从路径中获得扩展名/dir/subdir/file.bz2,但是我的路径有问题/dir/subdir/file-1.0.tar.bz2

如果可能的话,我更喜欢只使用 bash 而不使用外部程序的解决方案。

为了让我的问题更清楚,我正在创建一个 bash 脚本,只需通过extract path_to_file. 如何提取文件由脚本通过查看其压缩或存档类型来确定,可能是 .tar.gz、.gz、.bz2 等。我认为这应该涉及字符串操作,例如,如果我得到扩展名,.gz那么我应该检查它.tar之前是否有字符串.gz- 如果有,扩展名应该是.tar.gz.

gle*_*man 34

您可以通过仅对文件名进行模式匹配而不是提取扩展名两次来简化问题:

case "$filename" in
    *.tar.bz2) bunzip_then_untar ;;
    *.bz2)     bunzip_only ;;
    *.tar.gz)  untar_with -z ;;
    *.tgz)     untar_with -z ;;
    *.gz)      gunzip_only ;;
    *.zip)     unzip ;;
    *.7z)      do something ;;
    *)         do nothing ;;
esac
Run Code Online (Sandbox Code Playgroud)


Gil*_*il' 22

如果文件名是file-1.0.tar.bz2,则扩展名是bz2. 您用来提取扩展名 ( fileext=${filename##*.}) 的方法是完全有效的¹。

您如何决定是否要扩展名或tar.bz2不扩展名?你需要先回答这个问题。然后你可以找出哪个 shell 命令符合你的规范。bz20.tar.bz2

  • 一种可能的规范是扩展名必须以字母开头。对于一些常见的扩展,如7z,这种启发式方法失败,最好将其视为特殊情况。这是一个 bash/ksh/zsh 实现:

    basename=$filename; fileext=
    while [[ $basename = ?*.* &&
             ( ${basename##*.} = [A-Za-z]* || ${basename##*.} = 7z ) ]]
    do
      fileext=${basename##*.}.$fileext
      basename=${basename%.*}
    done
    fileext=${fileext%.}
    
    Run Code Online (Sandbox Code Playgroud)

    对于 POSIX 可移植性,您需要使用case语句进行模式匹配。

    while case $basename in
            ?*.*) case ${basename##*.} in [A-Za-z]*|7z) true;; *) false;; esac;;
            *) false;;
          esac
    do …
    
    Run Code Online (Sandbox Code Playgroud)
  • 另一个可能的规范是一些扩展表示编码并指示需要进一步剥离。这是一个 bash/ksh/zsh 实现(需要shopt -s extglob在 bash 和setopt ksh_globzsh 下):

    basename=$filename
    fileext=
    while [[ $basename = ?*.@(bz2|gz|lzma) ]]; do
      fileext=${basename##*.}.$fileext
      basename=${basename%.*}
    done
    if [[ $basename = ?*.* ]]; then
      fileext=${basename##*.}.$fileext
      basename=${basename%.*}
    fi
    fileext=${fileext%.}
    
    Run Code Online (Sandbox Code Playgroud)

    请注意,这被认为0file-1.0.gz.

¹和相关构造在POSIX 中,因此它们可以在任何非古董 Bourne 风格的 shell 中工作,例如 ash、bash、ksh 或 zsh。 ${VARIABLE##SUFFIX}

  • @uray:在这种特殊情况下有效,但这不是通用解决方案。考虑 [Maciej 的 `.patch.lzma` 示例](http://unix.stackexchange.com/questions/1571/bash-get-file-extension/1573#1573)。更好的启发式方法是考虑字符串 *after* 最后一个 `.`:如果它是压缩后缀(`.7z`、`.bz2`、`.gz`、...),则继续剥离。 (2认同)

Chr*_*ris 10

$ echo "thisfile.txt"|awk -F . '{print $NF}'
Run Code Online (Sandbox Code Playgroud)

对此的评论:http : //liquidat.wordpress.com/2007/09/29/short-tip-get-file-extension-in-shell-script/

  • 好吧,.tar.gz 实际上是 gzip 文件中的 tar,因此它确实可以从 gzip 文件中删除 gz 扩展名。 (6认同)
  • 不适用于“.tar.gz”扩展名 (2认同)

小智 5

这是我的做法:将点转换为换行符,通过管道tail,获取最后一行:

$> TEXT=123.234.345.456.456.567.678
$> echo $TEXT | tr . \\n | tail -n1
678
Run Code Online (Sandbox Code Playgroud)