$(echo "cd ..") 命令未找到

$(echo "cd ..") 命令未找到

好啊-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
}

脚步

  1. 如果没有传递参数,则转到上一个目录
  2. 如果传递了一个参数:
    1. 抓住pwd并分开/

    2. 迭代从队列后面走来的目录列表

    3. 如果当前目录与参数不匹配,则添加..到列表中

    4. 如果 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../../...

相关内容