在bash中快速而正确地获取目录或文件的基本名称的方法



我有这个代码:

get_base() { echo "${1##*/}"; }

这很好,直到我们有1个或更多尾随斜线

我已经找到了如何修复它的解决方案,但问题是我们需要启用extglob,而我没有想要:

ari@ari-gentoo ~ % x='/home/ari///'
ari@ari-gentoo ~ % echo "${x%%+(/)}"
/home/ari

然后我们可以obv将其保存到tmp var中,并运行basename对it的替代

不管怎样,我的问题是,有什么合适的方法吗而且它仍然很快(意味着不需要调用外部命令因为这个函数经常被调用(需要启用任何花哨的功能吗?

感谢您提前回答:(

问题和答案

  • 在Bash中获取文件路径参数中的最后一个目录名/文件名是否回答了您的问题

no,因为所有这些解决方案要么使用命令,要么有一个只去掉最后一个斜杠而不是倍数的替换表达式:

  • 你说的"适当"是什么意思

我的意思是"在不启用extglob或任何其他花哨功能的情况下实现">

这里有一种方法:

get_base() {
set -- "${1%"${1##*[!/]}"}"
printf '%sn' "${1##*/}"
}
$ get_base /home/oguz//
oguz
$ get_base /root
root
$ get_base /
$ get_base .bash_history
.bash_history

获取。。。在bash

作为对oguz-ismail正确答案的补充,我建议对这种函数使用-v标志,以减少分叉:

get_base() {
if [[ $1 == -v ]] ;then
local -n _res=$2
shift 2
else
local _res
fi
set -- "${1%"${1##*[!/]}"}"
printf -v _res %s "${1##*/}"
[[ ${_res@A} == _res=* ]] && echo "$_res"
}

这让你可以通过尝试这个功能

$ get_base /path/entry////
entry

但为了将结果存储到某个变量中,您将避免像这样无用的fork

myvar=$(get_base /path/entry////)

并使用首选语法:

$ get_base -v myvar /path/entry////
$ echo $myvar
entry

要成为拆分entrypath的函数:

get_base() {
if [[ $1 == -v ]] ;then
local -n _res=$2
shift 2
else
local _res
fi
set -- "${1%"${1##*[!/]}"}"
printf -v _res %s "${1##*/}"
[[ ${_res@A} == _res=* ]] &&
echo "$_res" "${1%/$_res}" && return
printf -v _res[1] %s "${1%/$_res}"
}

然后:

$ get_base /path/to/entry////
entry /path/to

$ get_base -v myvar /path/to/entry////
$ declare -p myvar 
declare -a myvar=([0]="entry" [1]="/path/to")
$ echo ${myvar[0]}
entry
$ echo ${myvar[1]}
/path/to

带分隔的unicode文件名:

$ get_base -v myvar '/path/to/some dir/some loved file ♥♥♥.xtns'
$ declare -p myvar 
declare -a myvar=([0]="some loved file ♥♥♥.xtns" [1]="/path/to/some dir")

想法:

get_base() { [[ $1 =~ ([^/]*)/*$ ]]; echo "${BASH_REMATCH[1]}"; };
get_base() { while [[ "${1%/}" != "$1" ]]; do set -- "${1%%/}"; done; echo "${1##*/}"; }

最新更新