function
我的档案里有一份.bashrc
。我知道它的作用,它会增加 X 个目录cd
这里是:
up()
{
local d=""
limit=$1
for ((i=1 ; i <= limit ; i++))
do
d=$d/..
done
d=$(echo $d | sed 's/^\///')
if [ -z "$d" ]; then
d=..
fi
cd $d
}
但你能为我解释一下这三件事吗?
d=$d/..
sed 's/^\///'
d=..
为什么不这样做:
up()
{
limit=$1
for ((i=1 ; i <= limit ; i++))
do
cd ..
done
}
用法:
<<<>>>~$ up 3
<<<>>>/$
答案1
d=$d/..
添加/..
到变量的当前内容d
。d
从空开始,然后第一次迭代使其成为/..
,第二次迭代/../..
等等。sed 's/^\///'
删除第一个/
,因此/../..
变为../..
(这可以使用参数扩展 来完成d=${d#/}
)。d=..
仅在其条件的上下文中才有意义:if [ -z "$d" ]; then d=.. fi
这确保了如果
d
此时为空,您将转到父目录。 (up
不带参数相当于cd ..
。)
这种方法比迭代更好,cd ..
因为它保留了cd -
一步返回到上一目录(从用户的角度来看)的能力。
该函数可以简化:
up() {
local d=..
for ((i = 1; i < ${1:-1}; i++)); do d=$d/..; done
cd $d
}
这假设我们想要至少提升一级,并添加n - 1级别,因此我们不需要删除前导/
或检查空的$d
.
使用 Athena jot
(athena-jot
Debian 中的软件包):
up() { cd $(jot -b .. -s / "${1:-1}"); }
答案2
但你能为我解释一下这三件事吗?
d=$d/..
这会将 var 的当前内容
d
与var 连接起来/..
并将其分配回d
。
最终结果是制作d
一个重复的字符串,如/../../../..
.sed 's/^///'
从您发布的代码中
/
提供的字符串中删除前导(echo $d)。 可能更好地编写以避免反斜杠。d
sed 's|^/||'
另一种选择(更快更简单)是编写
d=${d#/}
.d=..
将字符串分配
..
给 vard
。
这只有作为确保d
至少有一..
如果测试if [ -z "$d" ]; then
表明 vard
为空。这只能发生,因为 sed 命令正在从 中删除一个字符d
。
如果不需要从 d 中删除字符,则不需要sed
orif
。
您问题中的代码始终会向上移动至少一个目录。
更好的
local d
足以确保变量为空,不需要其他任何东西。
但是,local 只在某些 shell 中有效,例如 bash 或 dash。具体来说,ksh
(asyash
) 没有local
命令。更便携的解决方案是:[ "$KSH_VERSION$YASH_VERSION" ] && typeset c='' d='' i='' || local c='' d='' i=''
语法
for((
不可移植。最好使用类似的东西:while [ "$((i+=1))" -lt "$limit" ]; do
强壮的。
如果赋予函数第一个参数的值可以是负数或文本,则该函数应该能够稳健地处理这些值。
首先,让我们将值限制为仅数字(我将使用c
forcount
):c=${1%%[!0-9]*}
然后将计数值限制为仅正值:
let "c = (c>0)?c:0"
这个函数很乐意接受 0 或任何文本(没有错误):
up()
{
[ "$KSH_VERSION$YASH_VERSION" ] && typeset c='' d='' i='' || local c='' d='' i=''
c=${1%%[!0-9]*}
c=$(((c>0)?c:0))
while [ "$((i+=1))" -le "$c" ]; do d="$d../"; done
echo \
cd "${d%/}" # Removing the trailing / is not really needed for cd
# but it is nice to know it could be done cleanly.
}
up 2
up 0
up asdf
echo \
当您测试了该功能后,请删除。