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

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

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解释器。

有更好的主意吗?


当前回答

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

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

第一行解释道:它匹配PATH.EXT或ANYTHING,并将其替换为EXT。如果匹配了ANYTHNG,则不会捕获EXT组。

其他回答

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

这对我有用:

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

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

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命令将任意数量的字符替换为行开头的“.”字符,而不使用任何字符(即,它删除从行开头到最后一个点的所有内容,包括所有内容)。这是一个贪婪的替代,这是默认操作。

~% FILE="example.tar.gz"

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

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

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

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

有关详细信息,请参阅Bash手册中的shell参数扩展。

只需使用${parameter%word}

在您的案例中:

${FILE%.*}

如果您想测试它,以下所有操作都可以,只需删除扩展即可:

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

使用示例文件/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