只从Bash脚本中的路径中获取文件名

我怎么能得到只有文件名没有扩展名和路径?

下面给我没有扩展,但我仍然有附加的路径:

source_file_filename_no_ext=${source_file%.*}
502306 次浏览

许多类unix操作系统都有一个basename可执行文件,用于非常类似的目的(路径为dirname):

pax> full_name=/tmp/file.txt
pax> base_name=$(basename ${full_name})
pax> echo ${base_name}
file.txt

不幸的是,它只给了你文件名,包括扩展名,所以你需要找到一种方法来剥离它。

所以,既然你必须这样做,你也可以找到一个方法,可以剥离路径而且扩展。

一种方法是(这是一个bash-only的解决方案,不需要其他可执行文件):

pax> full_name=/tmp/xx/file.tar.gz
pax> xpath=${full_name%/*}
pax> xbase=${full_name##*/}
pax> xfext=${xbase##*.}
pax> xpref=${xbase%.*}
pax> echo "path='${xpath}', pref='${xpref}', ext='${xfext}'"


path='/tmp/xx', pref='file.tar', ext='gz'

这个小片段设置了xpath(文件路径),xpref(文件前缀,你具体要求的内容)和xfext(文件扩展名)。

$ source_file_filename_no_ext=${source_file%.*}
$ echo ${source_file_filename_no_ext##*/}

下面是一个从路径中获取文件名的简单方法:

echo "$PATH" | rev | cut -d"/" -f1 | rev

要删除你可以使用的扩展名,假设文件名只有一个点(扩展名点):

cut -d"." -f1

basenamedirname解决方案更方便。这些是可供选择的命令:

FILE_PATH="/opt/datastores/sda2/test.old.img"
echo "$FILE_PATH" | sed "s/.*\///"

它像basename一样返回test.old.img

这是没有扩展名的salt文件名:

echo "$FILE_PATH" | sed -r "s/.+\/(.+)\..+/\1/"

它返回test.old

下面的语句给出了完整的路径,如dirname命令。

echo "$FILE_PATH" | sed -r "s/(.+)\/.+/\1/"

它返回/opt/datastores/sda2

还有更多的替代选项,因为正则表达式(regi ?)太棒了!

下面是一个简单的正则表达式来完成这项工作:

 regex="[^/]*$"

例子(grep):

 FP="/hello/world/my/file/path/hello_my_filename.log"
echo $FP | grep -oP "$regex"
#Or using standard input
grep -oP "$regex" <<< $FP

例子(awk):

 echo $FP | awk '{match($1, "$regex",a)}END{print a[0]}
#Or using stardard input
awk '{match($1, "$regex",a)}END{print a[0]} <<< $FP

如果你需要一个更复杂的正则表达式: 例如,你的路径被包装在一个字符串中

 StrFP="my string is awesome file: /hello/world/my/file/path/hello_my_filename.log sweet path bro."


#this regex matches a string not containing / and ends with a period
#then at least one word character
#so its useful if you have an extension


regex="[^/]*\.\w{1,}"


#usage
grep -oP "$regex" <<< $StrFP


#alternatively you can get a little more complicated and use lookarounds
#this regex matches a part of a string that starts with /  that does not contain a /
##then uses the lazy operator ? to match any character at any amount (as little as possible hence the lazy)
##that is followed by a space
##this allows use to match just a file name in a string with a file path if it has an exntension or not
##also if the path doesnt have file it will match the last directory in the file path
##however this will break if the file path has a space in it.


regex="(?<=/)[^/]*?(?=\s)"


#to fix the above problem you can use sed to remove spaces from the file path only
## as a side note unfortunately sed has limited regex capibility and it must be written out in long hand.
NewStrFP=$(echo $StrFP | sed 's:\(/[a-z]*\)\( \)\([a-z]*/\):\1\3:g')
grep -oP "$regex" <<< $NewStrFP

Regexes的整体解决方案:

这个函数可以给你带或不带linux文件路径扩展名的文件名,即使文件名有多个“。在里面。 它还可以处理文件路径中的空格以及文件路径是否嵌入或包装在字符串中
#you may notice that the sed replace has gotten really crazy looking
#I just added all of the allowed characters in a linux file path
function Get-FileName(){
local FileString="$1"
local NoExtension="$2"
local FileString=$(echo $FileString | sed 's:\(/[a-zA-Z0-9\<\>\|\\\:\)\(\&\;\,\?\*]*\)\( \)\([a-zA-Z0-9\<\>\|\\\:\)\(\&\;\,\?\*]*/\):\1\3:g')


local regex="(?<=/)[^/]*?(?=\s)"


local FileName=$(echo $FileString | grep -oP "$regex")


if [[ "$NoExtension" != "" ]]; then
sed 's:\.[^\.]*$::g' <<< $FileName
else
echo "$FileName"
fi
}


## call the function with extension
Get-FileName "my string is awesome file: /hel lo/world/my/file test/path/hello_my_filename.log sweet path bro."


##call function without extension
Get-FileName "my string is awesome file: /hel lo/world/my/file test/path/hello_my_filename.log sweet path bro." "1"

如果你不得不打乱一个窗口路径,你可以从这个开始:

 [^\\]*$
$ file=${$(basename $file_path)%.*}