好啊-bash: cd ..: command not found
。
我编写了一个脚本来遍历指定目录。它一直有效,但现在我不知道发生了什么变化。
$ type up
up is a function
up ()
{
local arg="$@";
if [ -z "$arg" ]; then
cd ..;
return 1;
fi;
local arr=();
local sep='/';
local IFS="$sep";
local DIRS;
read -ra DIRS <<< "$(pwd)";
for ((i=${#DIRS[@]}-1; i>=0; i-- ))
do
if [ "${DIRS[i]}" = "$arg" ]; then
local first=${arr[0]};
arr=("${arr[@]:1}");
$(printf "%s" "cd $first" "${arr[@]/#/$sep}" && echo "/");
return 1;
else
arr+=('..');
fi;
done;
echo "Directory \"$arg\" could not be found in path. Check spelling and try again." 1>&2;
return 0
}
脚步
- 如果没有传递参数,则转到上一个目录
- 如果传递了一个参数:
抓住
pwd
并分开/
迭代从队列后面走来的目录列表
如果当前目录与参数不匹配,则添加
..
到列表中如果 dir 与命令行 arg 匹配,则解包
..
,用 分隔/
,并将字符串作为命令执行printf "%s" "cd $first" "${arr[@]/#/$sep}" && echo "/" # printf "%s" "cd $first" : prints 'cd ..' (command & the first placeholder) # "${arr[@]/#/$sep}" : prints the remaining '..' joined by '/' # echo "/" : adds a trailing '/' to the relative path # which could have been included in the # previous step but separated for comprehension # Given, pwd = /Users/dev/workspace/project/foo # `up workspace` navigates to 'cd ../../'
调试(从终端)
> cd ..
# works as expected
> $(echo "cd ..")
# works as expected --> maybe something with the "/" is breaking it?
> $('cd ..')
# -bash: cd ..: command not found
> $('cd ../')
# -bash: cd ../: No such file or directory
> which cd
# /usr/bin/cd
> echo $PATH
# /usr/bin
> type cd
# cd is a shell builtin
> alias cd
# -bash: alias: cd: not found
> shopt expand_aliases
# expand_aliases on
在 OSX 上的 bash3.2 中,取消设置大部分环境变量(例如 CDPATH)或使用干净的环境(即 )打开 shellenv -i bash --noprofile --norc
没有帮助。
评论
我的 bash 有点生疏,所以请随时指出更好的方法,这是可维护的。我知道return
可能没有必要(或正确),并且我已经看到了一些find
实现,它们可能更有效,但更难以遵循。
答案1
$(echo "cd ..")
运行 shell 命令echo "cd .."
(即echo
带有单个参数 的命令cd ..
),获取输出 ( cd ..
),在空格上分割该输出(和通配符,尽管这在这里并不重要),获取两个单词cd
和..
,并cd
使用争论..
。这是一种仅运行 shell 命令的复杂且容易出错的方法cd ..
。
除了在这里,你设置了IFS
一个斜杠,所以单词分割部分不在空格上分割,而是在斜杠上分割。
因此,当您执行 eg 时$(echo "cd ../..")
,命令替换的结果不会拆分为cd
, ../..
,而是拆分为cd ..
, ..
。此处的空格现在是命令名称的一部分,就像您"cd .." ..
在 shell 命令行上输入的一样。
最好不要依靠分词来使其正确(特别是因为它会在目录名包含空格时中断),而是将命令和参数分开。在变量中构建目录名称并使用它,即:
dir=$(printf "../..")
cd -- "$dir"
或者也许更确切地说
printf -v dir "../.."
cd -- "$dir"
另外,您可能不需要那里printf
。您可以使用"${arr[*]}"
来获取与 的第一个字符连接的数组元素IFS
,因此使用 时IFS=/
,它将用斜杠连接它们。
例如:
arr=(.. .. ..)
IFS=/
dir="${arr[*]}"
设置dir
为../../..
.