关于脚本:只从bash脚本中的路径获取文件名

Get just the filename from a path in a Bash script

本问题已经有最佳答案,请猛点这里访问。

如何获取不带扩展名和路径的文件名?

以下内容不提供扩展名,但我仍附加了路径:

1
source_file_filename_no_ext=${source_file%.*}


大多数类似于Unix的操作系统都有一个用于非常相似目的的basename可执行文件(和dirname用于路径):

1
2
3
4
pax> a=/tmp/file.txt
pax> b=$(basename $a)
pax> echo $b
file.txt

很遗憾,这只是给了您文件名,包括扩展名,所以您还需要找到一种方法来去掉它。

因此,考虑到无论如何都必须这样做,您还可以找到一个方法,可以去掉路径和扩展名。

实现这一点的一种方法(这是一种仅限于bash的解决方案,不需要其他可执行文件):

1
2
3
4
5
6
7
8
9
10
pax> a=/tmp/xx/file.tar.gz
pax> xpath=${a%/*}
pax> xbase=${a##*/}
pax> xfext=${xbase##*.}
pax> xpref=${xbase%.*}
pax> echo;echo path=${xpath};echo pref=${xpref};echo ext=${xfext}

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

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


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

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

这将返回与basename类似的test.old.img

这是不带扩展名的salt文件名:

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

返回test.old

下面的语句给出了类似于dirname命令的完整路径。

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

返回/opt/datastores/sda2


以下是从路径获取文件名的简单方法:

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

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

1
cut -d"." -f1


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


1
$ file=${$(basename $file_path)%.*}


因为regex(regi?)棒极了!

下面是一个简单的regex来完成这项工作:

1
 regex="[^/]*$"

示例(GRIP):

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

实例(AWK):

1
2
3
 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

如果需要更复杂的regex:例如,您的路径被包装在一个字符串中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
 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

包含正则表达式的总解决方案:

这个函数可以为您提供Linux文件路径扩展名或不扩展名,即使文件名中有多个"."。它还可以处理文件路径中的空格,以及文件路径是否嵌入或包装在字符串中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#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"

如果您必须处理Windows路径,可以从以下路径开始:

1
 [^\\]*$