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

Kei*_*ith 338 bash shell scripting

如何在没有扩展名且没有路径的情况下获取文件名?

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

source_file_filename_no_ext=${source_file%.*}
Run Code Online (Sandbox Code Playgroud)

pax*_*blo 618

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

pax> a=/tmp/file.txt
pax> b=$(basename $a)
pax> echo $b
file.txt
Run Code Online (Sandbox Code Playgroud)

遗憾的是,它只是为您提供了文件名,包括扩展名,因此您需要找到一种方法来删除它.

所以,无论如何你必须这样做,你也可以找到一种方法来剥离路径扩展.

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

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
Run Code Online (Sandbox Code Playgroud)

那个小片段设置xpath(文件路径),xpref(文件前缀,你特别要求的)和xfext(文件扩展名).

  • @Keith:对于pathname,使用`path = $(dirname $ filename)`; 没有命令给你扩展本身,但@paxdiablo向你展示了shell如何做到这一点. (3认同)
  • 您可以在 [手册](http://linux.die.net/man/1/bash) 的**参数扩展** 下阅读更多有关 bash-only 解决方案的信息。 (3认同)

Fır*_*ÇÜK 46

basenamedirname解决方案更方便.这些是替代命令:

FILE_PATH="/opt/datastores/sda2/test.old.img"
echo "$FILE_PATH" | sed "s/.*\///"
Run Code Online (Sandbox Code Playgroud)

这将返回test.old.imgbasename.

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

echo "$FILE_PATH" | sed -r "s/.+\/(.+)\..+/\1/"
Run Code Online (Sandbox Code Playgroud)

它回来了test.old.

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

echo "$FILE_PATH" | sed -r "s/(.+)\/.+/\1/"
Run Code Online (Sandbox Code Playgroud)

它回来了 /opt/datastores/sda2


小智 23

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

echo "$PATH" | rev | cut -d"/" -f1 | rev
Run Code Online (Sandbox Code Playgroud)

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

cut -d"." -f1
Run Code Online (Sandbox Code Playgroud)

  • 这不是一个好的假设,并且有专门设计用于正确执行此操作的工具和命令. (7认同)
  • 此外,我不建议使用变量名称“PATH”,因为这可能与系统的“PATH”变量冲突 (2认同)

mih*_*hai 15

$ file=${$(basename $file_path)%.*}
Run Code Online (Sandbox Code Playgroud)

  • 这会在bash v4.4.7中返回"bad substitution".我认为FıratKÜÇÜK的sed解决方案更好,即$(basename $ the_file_path)| sed"s /\..*//" (5认同)
  • 我的意思是`echo $(basename $the_file_path) | sed "s/\..*//"` (3认同)
  • 对我来说,这也会在 Bash 4.2.46 中给出“错误替换”错误。但如果我替换运算符的顺序,即 file=$(basename ${file_path%.*}) (2认同)

gho*_*g74 12

$ source_file_filename_no_ext=${source_file%.*}
$ echo ${source_file_filename_no_ext##*/}
Run Code Online (Sandbox Code Playgroud)


jkd*_*dba 8

还有一些替代选项,因为正则表达式(regi?)非常棒!

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

 regex="[^/]*$"
Run Code Online (Sandbox Code Playgroud)

示例(grep):

 FP="/hello/world/my/file/path/hello_my_filename.log"
 echo $FP | grep -oP "$regex"
 #Or using standard input
 grep -oP "$regex" <<< $FP
Run Code Online (Sandbox Code Playgroud)

示例(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
Run Code Online (Sandbox Code Playgroud)

如果您需要更复杂的正则表达式: 例如,您的路径包含在字符串中.

 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
Run Code Online (Sandbox Code Playgroud)

使用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"
Run Code Online (Sandbox Code Playgroud)

如果你不得不搞乱一个Windows路径,你可以从这个开始:

 [^\\]*$       
Run Code Online (Sandbox Code Playgroud)