【问题标题】:Find the depth of the current path查找当前路径的深度
【发布时间】:2018-02-15 21:45:14
【问题描述】:

如何编写shell脚本来查找当前路径的深度?

假设我在:

/home/user/test/test1/test2/test3

它应该返回 6。

【问题讨论】:

  • 提示:使用string splitcount
  • 你为什么用“bash”和“fish”来标记这个问题?这两个 shell 不支持相同的语法。您的问题过于宽泛。
  • Kurtis,感谢您的参与。我在网上查看过,即使在 bash 中也找不到执行此操作的脚本。鉴于 fish 是新的,我没想到会有很多反应,所以我愿意得到一个 bash 脚本并尝试自己转换它。那是我的理性。抱歉,如果这是错误的做法。我可以删除标签吗?我会检查的。
  • 好吧,现在您删除了 bash 标签...隐式地使 Bash 特定的答案无效。
  • Banjamin,我非常感谢您撰写并提出解决方案。我不知道从帖子中删除标签会产生这样的效果。即使在 bash 中也没有人提出解决深度问题的问题,所以我恢复了标签,因为您的回答对于对 bash 感兴趣的人具有很大的价值。谢谢。

标签: linux bash shell unix fish


【解决方案1】:

使用 shell 参数扩展,无需外部命令:

$ var=${PWD//[!\/]}
$ echo ${#var}
6

第一个扩展删除所有不是/的字符;第二个打印var的长度。


POSIX shell 或 Bash 支持的详细说明(括号中的链接转到 POSIX 标准或 Bash 手册中的相应部分):

  • $PWD 包含当前工作目录的路径。 (sh/Bash)
  • ${<em>parameter</em>/<em>pattern</em>/<em>string</em>} 扩展将 parameter 扩展中第一个出现的 pattern 替换为 string(Bash)
    • 如果第一个斜线被加倍(如我们的例子),所有次出现的地方都会被替换。
    • 如果 string 为空,则 pattern 之后的斜线是可选的(如我们的例子)。
  • 模式[!\/] 是一个括号表达式,代表“除斜线之外的任何字符”。 (sh/Bash)
    • 斜线必须转义,\/,否则会被解释为模式的结尾。
    • ! 作为括号表达式中的第一个字符否定表达式:表达式中的任何字符 other 都与模式匹配。 POSIX sh 需要对! 的支持,并表示使用^ 的行为未定义; Bash 同时支持!^。请注意,这不是正则表达式中看到的括号表达式,其中只有 ^ 有效。
  • ${#<em>parameter</em>} 扩展为 parameter 的长度。 (sh/Bash)

【讨论】:

  • 你能解释一下[!\/]吗?在这种情况下,我不知道!。 +1 最简洁的方式 :) 也许你可以添加关于 wich shell 可以做到这一点的精度
  • @GillesQuenot ! 作为 shell 模式括号表达式中的否定字符是 POSIX 要求的,而 ^ 的行为未定义; Bash 支持!^。我将添加更多信息。
【解决方案2】:

fish中的一个简单方法:

count (string split / $PWD)

【讨论】:

    【解决方案3】:

    您可以计算当前路径中的斜杠数量:

    pwd | awk -F"/" '{print NF-1}'
    

    【讨论】:

      【解决方案4】:

      您可以使用管道来执行此操作。使用 -o 选项将字符串导入 grep。这会在新行上打印出每个“/”。再次管道到 wc -l 计算打印的行数。

      echo "$path_str" | grep -o '/' - | wc -l
      

      【讨论】:

      • 我喜欢这个,因为它可以在像 ash/dash 这样的最小外壳中工作。不过,您应该引用$path_str,否则如果您的字符串包含通配符,您可能会遇到令人讨厌的意外。顺便说一句,POSIX 需要$PWD,所以你可以使用它。
      • 关于报价的要点。你能澄清一下需要 $PWD 的 POSIX 吗?恐怕我还没有丰富的 linux 经验。
      • 你可以使用环境变量$PWD,而不是使用$path_str,你可以使用环境变量$PWD,如果shell想要兼容它就必须存在POSIX,这是一种兼容性标准。
      【解决方案5】:

      假设您没有尾随“/”,您可以只计算“/”。

      你会的

      • 删除所有不是“/”的内容

      • 计算结果字符串的长度

      在鱼中,这将通过类似的方式完成

      string replace --regex --all '[^/]' '' -- $PWD | string length
      

      正则表达式 - [^/] 这里匹配每个不是“/”的字符。使用“--all”,这将尽可能频繁地完成,并将其替换为'',即什么都没有。

      -- 是选项分隔符,因此参数中的任何内容都不会被解释为选项(否则,如果参数以“-a”开头,您会遇到问题)。

      $PWD 是当前目录。

      string length 只是输出其输入的长度。

      【讨论】:

      • 谢谢。如果我想将计数放入稍后检查的变量中。如何将输出的长度设置为数字(而不是字符串)?这行得通吗? "设置长度字符串替换 --regex --all '[^/]' '' -- $PWD" 然后我可以做 "if test $length -lt 7"
      • string length 确实将其转换为数字,因此您可以将其放入变量中并稍后使用。 set length (string replace --regex --all '[^/]' '' -- $PWD | string length); if test $length -lt 7.
      【解决方案6】:

      使用

      echo '/home/user/test/test1/test2/test3' | 
      perl -lne '@_ = split /\//; print scalar @_ -1'
      

      输出

      6
      

      【讨论】:

        【解决方案7】:

        你可以像这样使用find

        find / -printf "%d %p\n" 2>/dev/null | grep "$PWD$" | awk '{print $1}'
        

        也许不是最有效的,但可以很好地处理斜线。

        【讨论】: