所以我希望我的功能能够改变为最近修改的目录。
就是这个:
function cdrc { echo 'cd "$(ls -t | HEAD -1)"'; }
当我想更改为最近的目录时:
$~ cd Desktop/Folder
$~ cdrc
我得到:
-bash:桌面:未找到命令
答案1
为什么你的功能不起作用
原因如下:
- 我猜
echo
是用来测试语法之类的东西的。如果你想让函数执行你描述的操作,这是没有意义的。 - 大写
HEAD
。在 Linux 中应该是head
。我不确定其他操作系统是否可以运行bash
,并且head
。HEAD
在某些操作系统中可能有效或无效,但head
应该在任何地方都可以运行。 ls
不建议解析。一篇关于它的文章。您遇到的问题是ls
无法可靠地打印包含特殊字符或不可打印字符的名称。- 没有仅测试目录的逻辑,
cd
当没有目录时,您最终可能会尝试访问文件。 - 没有逻辑来处理当前工作目录为空的情况。
除了解析问题之外,所有这些问题都可以调试ls
。这是一个设计缺陷。如果你认为ls
限制不会困扰你,那么你可以采用以下解决方案这是另一个答案。
为了进行一些测试,您可以创建一个有问题的目录mkdir "$(echo -ne "foo\nbar")"
;ls
如果这是目录,那么基于解决方案的解决方案可能会失败。要删除有问题的目录,请cdrc
调用。cd
rmdir "$(echo -ne "foo\nbar")"
我设法创建了一个更安全的功能。
解决方案
function cdrc { cd "$(find -maxdepth 1 -mindepth 1 -type d -exec stat --printf "%Y %n\0" {} + | sort -znr | head -zn 1 | cut -f 2- -d " ")" ;}
解释
为了解释我的功能,我将更清楚地写出来。注意,\
行末的 表示bash
命令在下一行继续;因此,下面的代码被视为一行,可以将其作为整体粘贴到 interactive 中bash
。
function cdrc { \
cd "$( \
find -maxdepth 1 -mindepth 1 -type d -exec \
stat --printf "%Y %n\0" {} + |
sort -znr |
head -zn 1 |
cut -f 2- -d " " \
)" \
;}
流程如下:
- 首先
find
运行。它不会下降到子目录(-maxdepth 1
),也不会找到当前目录(-mindepth 1
)。它只找到目录(-type d
)。然后stat
运行命令(感谢-exec
):stat
打印最后数据修改的时间(%Y
,mtime,自纪元以来的秒数),单个空格和名称(%n
)。由于--printf
选项的原因,它不会添加换行符,而是解释\0
为应在每行末尾添加的空字符。{}
find -exec
是语法的一部分。在find
执行过程中,它会被目录名替换,因此stat
知道它的目标是什么。+
也是语法的一部分find -exec
。它导致find
传递多种的名称变为单个stat
(并且stat
可以处理)。这样stat
创建的进程更少,速度更快。
目前,我们有零行或多行。它们看起来类似于:
1493488341 directory name
1497365306 troublesome?directory name
但它们是以空字符结尾的,因此即使名称中包含麻烦的字符,它们也会得到正确处理。在第一列中,mtime 没有前导空格(我检查了stat
不同长度的数字的行为以确保无误),然后第一个空格将 mtime 与目录名称分开。
- 该输出被进一步处理:
sort
根据数值对行进行排序 (-n
),使用反向顺序 (-r
) 并使用以空字符结尾的字符串 (-z
)。这样,我们需要的目录现在就在第一行。- 然后
head
只留下第一行(-n 1
);它还被告知使用以空字符结尾的字符串(-z
)。 cut
剪切行,将空格视为分隔符 (-d " "
),并保留第二个字段及其后面的所有内容 (-f 2-
),即第一个空格后的所有内容。它适用于以空字符结尾的字符串 (-z
)。最终输出是所需的目录名称。
请注意,如果当前工作目录中没有目录,则输出将为空。
$(…)
被里面所有内容的输出所替换。此时我们有 或cd "some directory name"
。cd ""
前一个命令执行您想要的操作;后者(当没有目录时)不执行任何操作。
如果找到该目录后,该函数应该cd
被移动/重命名,则该函数将失败。如果函数运行时任何目录被移动/重命名,也可能会抛出错误。find
stat
答案2
如果要包含所有目录,即以点开头
function cdrc { cd "$(ls -1atp|grep -v '^\.\.\?/$'|grep '/$'|head -1)"; }
否则就简单多了
function cdrc { cd "$(ls -1tp|grep '/$'|head -1)"; }