我想分别获取文件名(不带扩展名)和扩展名。

到目前为止,我找到的最佳解决方案是:

NAME=`echo "$FILE" | cut -d'.' -f1`
EXTENSION=`echo "$FILE" | cut -d'.' -f2`

这是错误的,因为如果文件名包含多个,它就不起作用。字符。假设我有a.b.js,它会考虑a和b.js而不是a.b和js。

它可以在Python中用

file, ext = os.path.splitext(path)

但如果可能的话,我不希望仅仅为此启动Python解释器。

有更好的主意吗?


当前回答

IMHO已经给出了最佳解决方案(使用外壳参数扩展),并且是目前评级最佳的解决方案。

然而,我添加了一个仅使用dumbs命令的命令,这是无效的,没有人应该认真使用:

FILENAME=$(echo $FILE | cut -d . -f 1-$(printf $FILE | tr . '\n' | wc -l))
EXTENSION=$(echo $FILE | tr . '\n' | tail -1)

仅为好玩而添加:-)

其他回答

如果文件没有扩展名或文件名,这似乎不起作用。这是我正在使用的;它只使用内置文件名,并处理更多(但不是所有)病态文件名。

#!/bin/bash
for fullpath in "$@"
do
    filename="${fullpath##*/}"                      # Strip longest match of */ from start
    dir="${fullpath:0:${#fullpath} - ${#filename}}" # Substring from 0 thru pos of filename
    base="${filename%.[^.]*}"                       # Strip shortest match of . plus at least one non-dot char from end
    ext="${filename:${#base} + 1}"                  # Substring from len of base thru end
    if [[ -z "$base" && -n "$ext" ]]; then          # If we have an extension and no base, it's really the base
        base=".$ext"
        ext=""
    fi

    echo -e "$fullpath:\n\tdir  = \"$dir\"\n\tbase = \"$base\"\n\text  = \"$ext\""
done

下面是一些测试用例:

$ basename-and-extension.sh / /home/me/ /home/me/file /home/me/file.tar /home/me/file.tar.gz /home/me/.hidden /home/me/.hidden.tar /home/me/.. .
/:
    dir  = "/"
    base = ""
    ext  = ""
/home/me/:
    dir  = "/home/me/"
    base = ""
    ext  = ""
/home/me/file:
    dir  = "/home/me/"
    base = "file"
    ext  = ""
/home/me/file.tar:
    dir  = "/home/me/"
    base = "file"
    ext  = "tar"
/home/me/file.tar.gz:
    dir  = "/home/me/"
    base = "file.tar"
    ext  = "gz"
/home/me/.hidden:
    dir  = "/home/me/"
    base = ".hidden"
    ext  = ""
/home/me/.hidden.tar:
    dir  = "/home/me/"
    base = ".hidden"
    ext  = "tar"
/home/me/..:
    dir  = "/home/me/"
    base = ".."
    ext  = ""
.:
    dir  = ""
    base = "."
    ext  = ""

这是AWK的代码。这可以做得更简单。但我不擅长AWK。

filename$ ls
abc.a.txt  a.b.c.txt  pp-kk.txt
filename$ find . -type f | awk -F/ '{print $2}' | rev | awk -F"." '{$1="";print}' | rev | awk 'gsub(" ",".") ,sub(".$", "")'
abc.a
a.b.c
pp-kk
filename$ find . -type f | awk -F/ '{print $2}' | awk -F"." '{print $NF}'
txt
txt
txt

好的,如果我理解正确,这里的问题是如何获取具有多个扩展名的文件的名称和完整扩展名,例如stuff.tar.gz。

这对我有用:

fullfile="stuff.tar.gz"
fileExt=${fullfile#*.}
fileName=${fullfile%*.$fileExt}

这将为您提供文件名和扩展名.tar.gz。它适用于任何数量的扩展,包括0。希望这对有同样问题的人有所帮助=)

魔术文件识别

除了关于堆栈溢出问题的许多好答案之外,我还想补充一点:

在Linux和其他unixen下,有一个名为file的神奇命令,它通过分析文件的一些第一个字节来进行文件类型检测。这是一个非常旧的工具,最初用于打印服务器(如果不是为…创建的,我不确定)。

file myfile.txt
myfile.txt: UTF-8 Unicode text

file -b --mime-type myfile.txt
text/plain

标准扩展可以在/etc/mime.types中找到(在我的Debian GNU/Linux桌面上。请参阅man file和man mime.types.也许您必须安装文件实用程序和mime支持包):

grep $( file -b --mime-type myfile.txt ) </etc/mime.types
text/plain      asc txt text pot brf srt

您可以创建一个bash函数来确定正确的扩展。有一个小样本(不完美):

file2ext() {
    local _mimetype=$(file -Lb --mime-type "$1") _line _basemimetype
    case ${_mimetype##*[/.-]} in
        gzip | bzip2 | xz | z )
            _mimetype=${_mimetype##*[/.-]}
            _mimetype=${_mimetype//ip}
            _basemimetype=$(file -zLb --mime-type "$1")
            ;;
        stream )
            _mimetype=($(file -Lb "$1"))
            [ "${_mimetype[1]}" = "compressed" ] &&
                _basemimetype=$(file -b --mime-type - < <(
                        ${_mimetype,,} -d <"$1")) ||
                _basemimetype=${_mimetype,,}
            _mimetype=${_mimetype,,}
            ;;
        executable )  _mimetype='' _basemimetype='' ;;
        dosexec )     _mimetype='' _basemimetype='exe' ;;
        shellscript ) _mimetype='' _basemimetype='sh' ;;
        * )
            _basemimetype=$_mimetype
            _mimetype=''
            ;;
    esac
    while read -a _line ;do
        if [ "$_line" == "$_basemimetype" ] ;then
            [ "$_line[1]" ] &&
                _basemimetype=${_line[1]} ||
                _basemimetype=${_basemimetype##*[/.-]}
            break
        fi
        done </etc/mime.types
    case ${_basemimetype##*[/.-]} in
        executable ) _basemimetype='' ;;
        shellscript ) _basemimetype='sh' ;;
        dosexec ) _basemimetype='exe' ;;
        * ) ;;
    esac
    [ "$_mimetype" ] && [ "$_basemimetype" != "$_mimetype" ] &&
      printf ${2+-v} $2 "%s.%s" ${_basemimetype##*[/.-]} ${_mimetype##*[/.-]} ||
      printf ${2+-v} $2 "%s" ${_basemimetype##*[/.-]}
}

此函数可以设置稍后可以使用的Bash变量:

(灵感来自@Petersh正确答案):

filename=$(basename "$fullfile")
filename="${filename%.*}"
file2ext "$fullfile" extension

echo "$fullfile -> $filename . $extension"

您可以使用basename。

例子:

$ basename foo-bar.tar.gz .tar.gz
foo-bar

您确实需要为basename提供要删除的扩展名,但是如果您总是使用-z执行tar,那么您知道扩展名将是.tar.gz。

这应该可以满足您的需要:

tar -zxvf $1
cd $(basename $1 .tar.gz)