提取文件名和扩展名中的Bash(Extract filename and extension in

2019-07-19 06:29发布

我想单独获得的文件名(不含扩展名)和扩展。

我迄今发现的最好的解决办法是:

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

这是错误的,因为如果文件名中包含多个它不工作. 字符。 如果,让我们说,我有abjs ,它会考虑ab.js ,而不是abjs

它可以在Python中很容易做到用

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

但我更喜欢如果可能的话,不要启动一个Python解释只是为了这个。

任何更好的想法?

Answer 1:

首先,获取文件名不带路径:

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

或者,你可以专注于最后一个“/”的路径,而不是的“” 这应该工作,即使你有不可预知的文件扩展名:

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

您可能要检查的文件:

  • 在上一节“网络3.5.3壳牌参数扩展 ”
  • 在部分bash的手册页被称为“参数扩展”


Answer 2:

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

有关更多细节,参见壳参数扩展在Bash手册。



Answer 3:

通常你已经知道的扩展,所以你可能希望使用:

basename filename .extension

例如:

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

我们得到

filename


Answer 4:

您可以使用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:

这似乎不如果文件没有扩展名,或者没有文件名的工作。 下面是我使用的是什么; 它仅使用内建并处理多个(但不是全部)的病理文件名。

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


Answer 6:

您可以使用basename

例:

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

你需要提供基本名称与应去掉了扩展,但是如果你总是执行tar-z那么你知道分机将是.tar.gz

这应该做你想要什么:

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


Answer 7:

pax> echo a.b.js | sed 's/\.[^.]*$//'
a.b
pax> echo a.b.js | sed 's/^.*\.//'
js

工作得很好,所以你可以使用:

pax> FILE=a.b.js
pax> NAME=$(echo "$FILE" | sed 's/\.[^.]*$//')
pax> EXTENSION=$(echo "$FILE" | sed 's/^.*\.//')
pax> echo $NAME
a.b
pax> echo $EXTENSION
js

该命令的方式,工作原理如下:

该命令NAME替换一个"." 字符后跟任意数量的非"." 字符到行的末尾,什么也没有(即,它消除一切从最终的"."到该行的末尾,包括在内)。 这基本上是使用正则表达式诡计一个非贪婪取代。

该命令EXTENSION代用品后跟一个任意数目的字符"." 字符在该行的开始,什么也没有(即,它消除一切从该行的开始到最后的点,包括在内)。 这是一个贪婪的替代这是默认的行动。



Answer 8:

梅伦写在博客中评论:

使用bash,这里还有${file%.*}获得的文件名没有扩展名和${file##*.}独自得到扩展。 那是,

file="thisfile.txt"
echo "filename: ${file%.*}"
echo "extension: ${file##*.}"

输出:

filename: thisfile
extension: txt


Answer 9:

您可以使用cut命令删除最后两个扩展(在".tar.gz"部分):

$ echo "foo.tar.gz" | cut -d'.' --complement -f2-
foo

正如克莱顿·休斯的评论指出,这不会对问题的实际例子的工作。 因此,作为一种替代我建议使用sed与扩展正则表达式,如下所示:

$ echo "mpc-1.0.1.tar.gz" | sed -r 's/\.[[:alnum:]]+\.[[:alnum:]]+$//'
mpc-1.0.1

它的工作原理无条件删除最后两个(字母和数字)扩展。

[评论后再次更新安德斯林达尔]



Answer 10:

无需费心awksed ,甚至perl这个简单的任务。 有一个纯击, os.path.splitext()只使用参数扩展兼容的解决方案。

参考实现

文件的os.path.splitext(path)

分裂路径名路径成一对(root, ext) ,使得root + ext == path ,和ext是空的或用一个周期开始,并且包含至多一个周期。 对基名领导期间被忽略; splitext('.cshrc')返回('.cshrc', '')

Python代码:

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

实施猛砸

尊重领导时期

root="${path%.*}"
ext="${path#"$root"}"

忽略主导时期

root="${path#.}";root="${path%"$root"}${root%.*}"
ext="${path#"$root"}"

测试

下面是测试案例的忽略导致周期执行,这应符合在每个输入Python的参考实现。

|---------------|-----------|-------|
|path           |root       |ext    |
|---------------|-----------|-------|
|' .txt'        |' '        |'.txt' |
|' .txt.txt'    |' .txt'    |'.txt' |
|' txt'         |' txt'     |''     |
|'*.txt.txt'    |'*.txt'    |'.txt' |
|'.cshrc'       |'.cshrc'   |''     |
|'.txt'         |'.txt'     |''     |
|'?.txt.txt'    |'?.txt'    |'.txt' |
|'\n.txt.txt'   |'\n.txt'   |'.txt' |
|'\t.txt.txt'   |'\t.txt'   |'.txt' |
|'a b.txt.txt'  |'a b.txt'  |'.txt' |
|'a*b.txt.txt'  |'a*b.txt'  |'.txt' |
|'a?b.txt.txt'  |'a?b.txt'  |'.txt' |
|'a\nb.txt.txt' |'a\nb.txt' |'.txt' |
|'a\tb.txt.txt' |'a\tb.txt' |'.txt' |
|'txt'          |'txt'      |''     |
|'txt.pdf'      |'txt'      |'.pdf' |
|'txt.tar.gz'   |'txt.tar'  |'.gz'  |
|'txt.txt'      |'txt'      |'.txt' |
|---------------|-----------|-------|

检测结果

所有测试通过。



Answer 11:

下面是一些其他建议(主要在awk ),包括一些先进的使用情况,像软件包提取版本号。

f='/path/to/complex/file.1.0.1.tar.gz'

# Filename : 'file.1.0.x.tar.gz'
    echo "$f" | awk -F'/' '{print $NF}'

# Extension (last): 'gz'
    echo "$f" | awk -F'[.]' '{print $NF}'

# Extension (all) : '1.0.1.tar.gz'
    echo "$f" | awk '{sub(/[^.]*[.]/, "", $0)} 1'

# Extension (last-2): 'tar.gz'
    echo "$f" | awk -F'[.]' '{print $(NF-1)"."$NF}'

# Basename : 'file'
    echo "$f" | awk '{gsub(/.*[/]|[.].*/, "", $0)} 1'

# Basename-extended : 'file.1.0.1.tar'
    echo "$f" | awk '{gsub(/.*[/]|[.]{1}[^.]+$/, "", $0)} 1'

# Path : '/path/to/complex/'
    echo "$f" | awk '{match($0, /.*[/]/, a); print a[0]}'
    # or 
    echo "$f" | grep -Eo '.*[/]'

# Folder (containing the file) : 'complex'
    echo "$f" | awk -F'/' '{$1=""; print $(NF-1)}'

# Version : '1.0.1'
    # Defined as 'number.number' or 'number.number.number'
    echo "$f" | grep -Eo '[0-9]+[.]+[0-9]+[.]?[0-9]?'

    # Version - major : '1'
    echo "$f" | grep -Eo '[0-9]+[.]+[0-9]+[.]?[0-9]?' | cut -d. -f1

    # Version - minor : '0'
    echo "$f" | grep -Eo '[0-9]+[.]+[0-9]+[.]?[0-9]?' | cut -d. -f2

    # Version - patch : '1'
    echo "$f" | grep -Eo '[0-9]+[.]+[0-9]+[.]?[0-9]?' | cut -d. -f3

# All Components : "path to complex file 1 0 1 tar gz"
    echo "$f" | awk -F'[/.]' '{$1=""; print $0}'

# Is absolute : True (exit-code : 0)
    # Return true if it is an absolute path (starting with '/' or '~/'
    echo "$f" | grep -q '^[/]\|^~/'

所有用例是使用原始完整路径作为输入,而不依赖于中间结果。



Answer 12:

最小且最简单的解决方案(在单个线)为:

$ file=/blaabla/bla/blah/foo.txt
echo $(basename ${file%.*}) # foo


Answer 13:

接受的答案适用于典型的案例 ,但边缘的情况下 ,即失败

  • 对于没有扩展名的文件名(称为在这个答案的其余部分后缀 ), extension=${filename##*.}返回输入文件名,而不是一个空字符串。
  • extension=${filename##*.}不包括初始. 相反,公约。
    • 盲目前面加. 对于文件名不带后缀是行不通的。
  • filename="${filename%.*}"将成为空字符串,如果输入文件名开头. 并且不包含其它. 字符(例如, .bash_profile ) -违背约定。

---------

因此, 覆盖所有的边缘情况下可靠的解决方案的复杂性要求的功能 -参见下面的定义; 它可以返回路径的所有组件

调用示例:

splitPath '/etc/bash.bashrc' dir fname fnameroot suffix
# -> $dir == '/etc'
# -> $fname == 'bash.bashrc'
# -> $fnameroot == 'bash'
# -> $suffix == '.bashrc'

注意,输入路径后的参数被自由选择,位置变量
要跳过不感兴趣的变量那些之前到来,指定_ (使用扔掉的变量$_ )或'' ; 例如,要提取的文件名和根仅扩展,使用splitPath '/etc/bash.bashrc' _ _ fnameroot extension


# SYNOPSIS
#   splitPath path varDirname [varBasename [varBasenameRoot [varSuffix]]] 
# DESCRIPTION
#   Splits the specified input path into its components and returns them by assigning
#   them to variables with the specified *names*.
#   Specify '' or throw-away variable _ to skip earlier variables, if necessary.
#   The filename suffix, if any, always starts with '.' - only the *last*
#   '.'-prefixed token is reported as the suffix.
#   As with `dirname`, varDirname will report '.' (current dir) for input paths
#   that are mere filenames, and '/' for the root dir.
#   As with `dirname` and `basename`, a trailing '/' in the input path is ignored.
#   A '.' as the very first char. of a filename is NOT considered the beginning
#   of a filename suffix.
# EXAMPLE
#   splitPath '/home/jdoe/readme.txt' parentpath fname fnameroot suffix
#   echo "$parentpath" # -> '/home/jdoe'
#   echo "$fname" # -> 'readme.txt'
#   echo "$fnameroot" # -> 'readme'
#   echo "$suffix" # -> '.txt'
#   ---
#   splitPath '/home/jdoe/readme.txt' _ _ fnameroot
#   echo "$fnameroot" # -> 'readme'  
splitPath() {
  local _sp_dirname= _sp_basename= _sp_basename_root= _sp_suffix=
    # simple argument validation
  (( $# >= 2 )) || { echo "$FUNCNAME: ERROR: Specify an input path and at least 1 output variable name." >&2; exit 2; }
    # extract dirname (parent path) and basename (filename)
  _sp_dirname=$(dirname "$1")
  _sp_basename=$(basename "$1")
    # determine suffix, if any
  _sp_suffix=$([[ $_sp_basename = *.* ]] && printf %s ".${_sp_basename##*.}" || printf '')
    # determine basename root (filemane w/o suffix)
  if [[ "$_sp_basename" == "$_sp_suffix" ]]; then # does filename start with '.'?
      _sp_basename_root=$_sp_basename
      _sp_suffix=''
  else # strip suffix from filename
    _sp_basename_root=${_sp_basename%$_sp_suffix}
  fi
  # assign to output vars.
  [[ -n $2 ]] && printf -v "$2" "$_sp_dirname"
  [[ -n $3 ]] && printf -v "$3" "$_sp_basename"
  [[ -n $4 ]] && printf -v "$4" "$_sp_basename_root"
  [[ -n $5 ]] && printf -v "$5" "$_sp_suffix"
  return 0
}

test_paths=(
  '/etc/bash.bashrc'
  '/usr/bin/grep'
  '/Users/jdoe/.bash_profile'
  '/Library/Application Support/'
  'readme.new.txt'
)

for p in "${test_paths[@]}"; do
  echo ----- "$p"
  parentpath= fname= fnameroot= suffix=
  splitPath "$p" parentpath fname fnameroot suffix
  for n in parentpath fname fnameroot suffix; do
    echo "$n=${!n}"
  done
done

即行使功能测试代码:

test_paths=(
  '/etc/bash.bashrc'
  '/usr/bin/grep'
  '/Users/jdoe/.bash_profile'
  '/Library/Application Support/'
  'readme.new.txt'
)

for p in "${test_paths[@]}"; do
  echo ----- "$p"
  parentpath= fname= fnameroot= suffix=
  splitPath "$p" parentpath fname fnameroot suffix
  for n in parentpath fname fnameroot suffix; do
    echo "$n=${!n}"
  done
done

预期输出 - 注意边缘情况:

  • 不具有后缀的文件名
  • 文件名开头.考虑后缀的开始)
  • 在结束的输入路径/ (拖尾/被忽略)
  • 这只是一个文件名的输入路径( .被返回作为父路径)
  • 有超过一个文件名. -prefixed令牌(只有最后一个被认为是后缀):
----- /etc/bash.bashrc
parentpath=/etc
fname=bash.bashrc
fnameroot=bash
suffix=.bashrc
----- /usr/bin/grep
parentpath=/usr/bin
fname=grep
fnameroot=grep
suffix=
----- /Users/jdoe/.bash_profile
parentpath=/Users/jdoe
fname=.bash_profile
fnameroot=.bash_profile
suffix=
----- /Library/Application Support/
parentpath=/Library
fname=Application Support
fnameroot=Application Support
suffix=
----- readme.new.txt
parentpath=.
fname=readme.new.txt
fnameroot=readme.new
suffix=.txt


Answer 14:

我认为,如果你只需要在文件的名称,你可以试试这个:

FULLPATH=/usr/share/X11/xorg.conf.d/50-synaptics.conf

# Remove all the prefix until the "/" character
FILENAME=${FULLPATH##*/}

# Remove all the prefix until the "." character
FILEEXTENSION=${FILENAME##*.}

# Remove a suffix, in our case, the filename. This will return the name of the directory that contains this file.
BASEDIRECTORY=${FULLPATH%$FILENAME}

echo "path = $FULLPATH"
echo "file name = $FILENAME"
echo "file extension = $FILEEXTENSION"
echo "base directory = $BASEDIRECTORY"

这是所有= d。



Answer 15:

您可以强制切到显示各个领域和后续者加入-以场数。

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

所以,如果FILE是eth0.pcap.gz ,扩展名是pcap.gz

“ - ”使用相同的逻辑,你也可以用获取的文件名与切如下:

NAME=`basename "$FILE" | cut -d'.' -f-1`

这个工程即使没有任何扩展名的文件名。



Answer 16:

魔术文件识别

除了很多在这个堆栈溢出问题很好的答案我想补充:

在Linux和其他unixen,有一个神奇的命令命名的file ,通过分析文件的第一部分字节做类型检测。 这是一个非常古老的工具,initialy用于打印服务器(如果不是创造了...我不知道这一点)。

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

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

标准的扩展可以中找到/etc/mime.types (我上的Debian GNU / Linux桌面见。 man fileman mime.types也许你有安装。 file实用性和mime-support包):

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

您可以创建一个庆典来确定正确的扩展功能。 有一个小(不完美)示例:

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变量:

(这是从@Petesh正确答案的启发):

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

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


Answer 17:

好了,所以如果我理解正确的话,这里的问题是如何获得的名称,并有多个分机,例如,文件的全面推广stuff.tar.gz

这对我的作品:

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

这会给你stuff作为文件名和.tar.gz为扩展名。 它适用于任何数量的扩展,其中包括0。希望这有助于具有相同问题的人=)



Answer 18:

我使用下面的脚本

$ echo "foo.tar.gz"|rev|cut -d"." -f3-|rev
foo


Answer 19:

$ F = "text file.test.txt"  
$ echo ${F/*./}  
txt  

这迎合了多个点和空格的文件名,但如果没有扩展名,返回文件名本身。 易于检查,虽然; 只是测试文件名和扩展名是相同的。

当然这种方法并不确定为.tar.gz文件。 然而,可以在两个步骤来处理。 如果扩展名是GZ再检查一遍,看看是否也有焦油扩展。



Answer 20:

如何提取文件名和扩展名的

function split-filename-extension --description "Prints the filename and extension"
  for file in $argv
    if test -f $file
      set --local extension (echo $file | awk -F. '{print $NF}')
      set --local filename (basename $file .$extension)
      echo "$filename $extension"
    else
      echo "$file is not a valid file"
    end
  end
end

注意事项:在最后一个点,这与他们对点文件名行之有效拆分,但不能很好的与他们的点扩展。 参见下面的例子。

用法:

$ split-filename-extension foo-0.4.2.zip bar.tar.gz
foo-0.4.2 zip  # Looks good!
bar.tar gz  # Careful, you probably want .tar.gz as the extension.

很可能有更好的方法来做到这一点。 随意编辑我的答案,以改善它。


如果有一组有限的,你会被处理的扩展,你知道所有的人,试试这个:

switch $file
  case *.tar
    echo (basename $file .tar) tar
  case *.tar.bz2
    echo (basename $file .tar.bz2) tar.bz2
  case *.tar.gz
    echo (basename $file .tar.gz) tar.gz
  # and so on
end

并不一定需要提醒的是第一个例子,但你必须处理每一个案件,因此它可以根据你多少可以扩展期待更加繁琐。



Answer 21:

这里是代码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


Answer 22:

从建筑Petesh答案,如果只需要一个文件名,两者的路径和扩展名可以在一个单一的线剥离,

filename=$(basename ${fullname%.*})


Answer 23:

只需使用${parameter%word}

你的情况:

${FILE%.*}

如果你想测试一下,所有的后续工作,只是去掉扩展名:

FILE=abc.xyz; echo ${FILE%.*};
FILE=123.abc.xyz; echo ${FILE%.*};
FILE=abc; echo ${FILE%.*};


Answer 24:

一个简单的答案:

为了扩大对POSIX变量回答 ,请注意,你可以做更多有趣的图案。 因此,对这里的情况详细介绍,你可以简单地这样做:

tar -zxvf $1
cd ${1%.tar.*}

这将切断的.tar的最后一次出现。 <东西>。

更一般地,如果你想删除的最后一次出现。 <东西>。 <东西,别的>然后

${1.*.*}

应该正常工作。

链接上面的答案似乎是死了。 下面是一串字符串处理,你可以直接猛砸做,从TLDP的很好的解释 。



Answer 25:

如果您还想允许扩展,这是我能想出的最短:

echo 'hello.txt' | sed -r 's/.+\.(.+)|.*/\1/' # EXTENSION
echo 'hello.txt' | sed -r 's/(.+)\..+|(.*)/\1\2/' # FILENAME

第一行解释:它匹配PATH.EXT或任何与EXT替换它。 如果说有什么是匹配的,在内线组没有捕获。



Answer 26:

很大程度上抵消@ mklement0的优秀,并塞满随机的,有用的bash化的-以及其他的答案,这样/其他问题/“织补互联网” ......我把它包起来都在一点点,稍微理解,我(或你)可重复使用的功能 .bash_profile是负责什么的(我认为)应该是一个更强大的版本, dirname / basename / 你有什么 ..

function path { SAVEIFS=$IFS; IFS=""   # stash IFS for safe-keeping, etc.
    [[ $# != 2 ]] && echo "usage: path <path> <dir|name|fullname|ext>" && return    # demand 2 arguments
    [[ $1 =~ ^(.*/)?(.+)?$ ]] && {     # regex parse the path
        dir=${BASH_REMATCH[1]}
        file=${BASH_REMATCH[2]}
        ext=$([[ $file = *.* ]] && printf %s ${file##*.} || printf '')
        # edge cases for extensionless files and files like ".nesh_profile.coffee"
        [[ $file == $ext ]] && fnr=$file && ext='' || fnr=${file:0:$((${#file}-${#ext}))}
        case "$2" in
             dir) echo      "${dir%/*}"; ;;
            name) echo      "${fnr%.*}"; ;;
        fullname) echo "${fnr%.*}.$ext"; ;;
             ext) echo           "$ext"; ;;
        esac
    }
    IFS=$SAVEIFS
}     

用例...

SOMEPATH=/path/to.some/.random\ file.gzip
path $SOMEPATH dir        # /path/to.some
path $SOMEPATH name       # .random file
path $SOMEPATH ext        # gzip
path $SOMEPATH fullname   # .random file.gzip                     
path gobbledygook         # usage: -bash <path> <dir|name|fullname|ext>


Answer 27:

使用的示例文件/Users/Jonathan/Scripts/bash/MyScript.sh ,这样的代码:

MY_EXT=".${0##*.}"
ME=$(/usr/bin/basename "${0}" "${MY_EXT}")

将导致${ME}MyScript${MY_EXT}.sh


脚本:

#!/bin/bash
set -e

MY_EXT=".${0##*.}"
ME=$(/usr/bin/basename "${0}" "${MY_EXT}")

echo "${ME} - ${MY_EXT}"

一些测试:

$ ./MyScript.sh 
MyScript - .sh

$ bash MyScript.sh
MyScript - .sh

$ /Users/Jonathan/Scripts/bash/MyScript.sh
MyScript - .sh

$ bash /Users/Jonathan/Scripts/bash/MyScript.sh
MyScript - .sh


Answer 28:

从上面的答案,最短oneliner模仿Python的

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

假设你的文件确实有一个延伸,是

EXT="${PATH##*.}"; FILE=$(basename "$PATH" .$EXT)


Answer 29:

IMHO最好的解决方案已经被给定(使用壳参数扩展),并且在此时最好额定之一。

但是我想补充这一个刚刚用在dumbs命令,它是没有效率的,并且没有人严重应该永远使用:

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

新增只是为了好玩 :-)



Answer 30:

为了使DIR更有用(在没有路径的本地文件指定为输入的情况下),我做了以下内容:

# Substring from 0 thru pos of filename
dir="${fullpath:0:${#fullpath} - ${#filename}}"
if [[ -z "$dir" ]]; then
    dir="./"
fi

这可以让你做一些有用的东西像添加后缀到输入文件名前缀为:

outfile=${dir}${base}_suffix.${ext}

testcase: foo.bar
dir: "./"
base: "foo"
ext: "bar"
outfile: "./foo_suffix.bar"

testcase: /home/me/foo.bar
dir: "/home/me/"
base: "foo"
ext: "bar"
outfile: "/home/me/foo_suffix.bar"


文章来源: Extract filename and extension in Bash