在Bash中提取文件名和扩展名

bash string filenames


我想分别得到文件名(不含扩展名)和扩展名。

目前我找到的最佳解决方案是。

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

这是错误的,因为如果文件名包含多个,则无法使用 . 字符。如果说我有 a.b.js ,它将考虑 ab.js ,而不是 a.bjs

可以在Python中用

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

但如果可能的话,我希望不要为了这个而启动Python解释器。

有什么更好的办法吗?




Answer 1 Petesh


首先,获取不含路径的文件名。

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

另外,你可以关注路径的最后一个'/',而不是'.',即使你的文件扩展名无法预测,也应该可以使用。

filename="${fullfile##*/}"

你可能要检查文件。




Answer 2 Juliano


~% FILE="example.tar.gz"

~% echo "${FILE%%.*}"
example

~% echo "${FILE%.*}"
example.tar

~% echo "${FILE#*.}"
tar.gz

~% echo "${FILE##*.}"
gz

有关更多详细信息,请参见Bash手册中的shell参数扩展




Answer 3 Tomi Po


通常你已经知道了扩展名,所以你可能希望使用。

basename filename .extension

例如:

basename /path/to/dir/filename.txt .txt

而我们得到

filename



Answer 4 sotapme


你可以使用POSIX参数扩展的魔力。

bash-3.2$ FILENAME=somefile.tar.gz
bash-3.2$ echo "${FILENAME%%.*}"
somefile
bash-3.2$ echo "${FILENAME%.*}"
somefile.tar

需要注意的是,如果您的文件名采用 ./somefile.tar.gz 格式,则 echo ${FILENAME%%.*} 会贪婪地删除最长匹配项 . 并且您会有空字符串。

(您可以使用一个临时变量解决此问题:

FULL_FILENAME=$FILENAME
FILENAME=${FULL_FILENAME##*/}
echo ${FILENAME%%.*}

)


网站解释了更多。

${variable%pattern}
  Trim the shortest match from the end
${variable##pattern}
  Trim the longest match from the beginning
${variable%%pattern}
  Trim the longest match from the end
${variable#pattern}
  Trim the shortest match from the beginning



Answer 5 Doctor J


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

#!/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  = ""