我的意思是,假设我们有以下目录
Dropbox(文件夹)
---> 鲍勃(文件夹)
-------->2017(文件夹)
------------> 图像(文件夹)
----------------> 图像.png (文件)
我可以这样做
cd Dropbox
,但随后我必须手动导航到最深的目录images
。
有这样的命令
cd Dropbox:deepest directory
可以带我去吗Dropbox/Bob/2017/images
?
如果任一级别存在平局,则停止在该级别
答案1
和zsh
:
bydepth() REPLY=${REPLY//[^\/]}
cd Dropbox/**/*(D/O+bydepth[1])
我们定义一个bydepth
排序函数,返回包含未删除字符的文件/
(因此转换后的顺序是在深度上),并使用**/
带有 glob 限定符的递归 globbing(是任何级别的子目录):
D
还要考虑隐藏目录/
仅适用于目录O+bydepth
:按深度反向排序[1]
仅获取第一个(排序后)。
使用bash
GNU 工具,相当于:
IFS= read -rd '' deepest < <(find Dropbox/ -type d -print0 |
awk -v RS='\0' -v ORS='\0' -F / '
NF > max {max = NF; deepest = $0}
END {if (max) print deepest}') && cd -- "$deepest"
(如果出现平局,所选择的方法不一定与zsh
方法中的相同)。
有了新的额外要求,事情就会变得更加复杂。基本上,如果我理解正确,在有联系的情况下,它应该更改为最大深度的所有这些目录的最深公共父目录。和zsh
:
cd_deepest() {
setopt localoptions rematchpcre
local REPLY dirs result dir match
dirs=(${1:-.}/**/*(ND/nOne:'
REPLY=${#REPLY//[^\/]}-$REPLY':))
(($#dirs)) || return
result=$dirs[1]
for dir ($dirs[2,-1]) {
[[ $result//$dir =~ '^([^-]*-.*)/.*//\1/' ]] || break
result=$match[1]
}
cd -- ${result#*-} && print -rD -- $PWD
}
例子:
$ tree Dropbox
Dropbox
├── a
│ └── b
│ ├── 1
│ │ └── x
│ └── 2
│ └── x
└── c
└── d
└── e
9 directories, 0 files
$ cd_deepest Dropbox
~/Dropbox/a/b
(Dropbox/a/b/1/x
和Dropbox/a/b/2/x
是最深的,我们将其更改为它们最深的共同父级(Dropbox/a/b
))。
答案2
find . -type d -print0 | while IFS= read -r -d $'\0' line; do echo -n $(echo "$line" | grep -o '/' | wc -l); echo " $line"; done | sort | tail -1 | cut -d' ' -f2-
在 macOS (bash) 和 Arch Linux(zsh 和 bash)上进行了测试。
find . -type d
用于查找当前路径下的所有目录。-print0
结合read
使用来处理 find 的输出,也用于可能包含空格的目录。grep -o
用于从路径中挑选出斜杠。wc -l
用于计算斜杠的数量。sort
和tail
用于挑选包含最多斜杠的路径。cut
用于丢弃斜线号并仅显示最深目录的路径。
答案3
这是一个以 bash 为中心的版本;它依赖于以下 bash 功能:
- globstar shell 选项启用目录和子目录扩展
**/
- 读取支持数组的内容计算目录深度
cdd() {
local _cdd_unset_globstar=0
shopt -q globstar || _cdd_unset_globstar=1
shopt -s globstar
local _cdd_deepest=$1
local _cdd_level=1
local _cdd_array=()
for d in "${1}/"**/
do
IFS=/ read -r -d '' -a _cdd_array <<< "$d" || true
if [ "${#_cdd_array[*]}" -gt "$_cdd_level" ]
then
_cdd_deepest=$d
_cdd_level=${#_cdd_array[*]}
fi
done
cd -- "$_cdd_deepest" && true
local _cdd_ret="$?"
[ "$_cdd_unset_globstar" -eq 1 ] && shopt -u globstar
return "$_cdd_ret"
}
该函数执行以下操作:
- 检查 globstar shell 选项是否已设置;如果没有,那么我们保存一个标志以在最后重置选项。
- 初始化当前已知最深的目录及其级别(分别为
$1
和1
)。 - 展开给定参数下的每个子目录并循环遍历它们。
- 对于每个子目录,将其读入一个数组,以
/
;分隔。计算数组中元素的数量并将其与当前已知的最深目录级别进行比较。如果更深,请重置这些变量。 - 一旦我们有了最深的子目录,
cd
就可以了。 - 如果我们应该重置 globstar shell 选项,请这样做。
如果您认为使用子 shell 来设置 shell 选项更清晰,那么您可以使用两个函数来处理它:一个包装器和一个执行上述操作的子 shell 调用函数:
cdd_helper() (
shopt -s globstar
_cdd_deepest=$1
_cdd_level=1
for d in "${1}/"**/
do
IFS=/ read -r -d '' -a _cdd_array <<< "$d" || true
if [ "${#_cdd_array[*]}" -gt "$_cdd_level" ]
then
_cdd_deepest=$d
_cdd_level=${#_cdd_array[*]}
fi
done
printf "%s" "$_cdd_deepest"
)
cdd() {
cd -- "$(cdd_helper "$1")"
}
答案4
第一种方法 - 递归,我认为最好的方法。
用法:将函数加载rcd
到 bash 中source recur_cd.sh
,然后测试它:rcd some_dir
。
rcd () {
if [ ! -d "$*" ]; then
return 121
else
rcd "${*}"*/
fi
if (($? == 121)); then
cd "$*"
fi
}
第二种方式 - 命令 find (这里有两个变体)。
用法:首先,通过以下命令将两个内部函数(dcd1
和dcd2
)加载到 中: 。函数的作用相同,但实现方式不同。bash
source deep_cd.sh
然后,测试一下:
dcd1 dir # first variant
pwd
cd - # return back for further testing`<br>
dcd2 dir # second variant
pwd
# and so on.
深CD.sh
#!/bin/bash
# first variant, support filenames with spaces, work by awk mainly
dcd1 () {
cd "$(find "$1" -type d -printf "%d %p\n" | sort | awk '{
a[$1]++;
tmp_num=$1;
sub("^[0-9]* ", "", $0);
path = $0;
if (a[tmp_num] == 2) { sub("[^/]*$", ""); path = $0; exit; }
}
END { print path; }')"
}
# second variant, support filenames with spaces - more programs
# used (cut, uniq, tail), awk only prints the path, doesn't search it
dcd2 () {
str=$(find "$1" -type d -printf "%d %p\n" | sort)
num=$(cut -d " " -f 1 <<< "$str" | uniq -u | tail -n 1)
path=$(awk -v n=$num 'NR == n+1 { $1=""; print $0; }' <<< "$str")
cd "${path# }"
}
第三种方法 - readline 宏的使用。
bind '"\e\C-i":"\C-i\C-i\C-i\C-i"'
就这样 :)
解释:
bind
- 读help bind
。它是用于键绑定的 readline 函数。\e\C-i
- Ctlr+ Alt+ i- 新的键组合,当按下它时,它会在出现两个或更多目录之前自动完成系列。\C-i
与 相同Tab,意思是“完整”。您需要的\C-i
目录深度与您想象的一样多。如果假设有 10 个级别,那么您需要 10 个\C-i
块。不过,选择中间数量的块可能会更方便,例如 3 或 4,然后Alt + Ctrl + i
在需要时按组合键两次。它将防止输出重复(请参阅“测试”部分)
如果您想让此行为永久存在,请将此行添加到.bashrc
测试
cd o # then Alt + Ctrl + i
cd one/two/three/four/ # directory has changed to deepest
cd A # then Alt + Ctrl + i
cd A/B/C/ # directory has changed to deepest
D/ E/ # and two inner directories appear
~/deepest_dir$ cd A/B/C/ # one drawback here - if deepest
D/ E/ # directory is reached, then completion
~/deepest_dir$ cd A/B/C/ # works idle and print duplicating
# output, so may be worth shrinks 'C-i'
# blocks amount in the binding string