调用 bash 函数无法正常工作,无法更改到最近的目录?

调用 bash 函数无法正常工作,无法更改到最近的目录?

所以我希望我的功能能够改变为最近修改的目录。

就是这个:

function cdrc { echo 'cd "$(ls -t | HEAD -1)"'; }

当我想更改为最近的目录时:

$~ cd Desktop/Folder
$~ cdrc

我得到:

-bash:桌面:未找到命令

答案1

为什么你的功能不起作用

原因如下:

  • 我猜echo是用来测试语法之类的东西的。如果你想让函数执行你描述的操作,这是没有意义的。
  • 大写HEAD。在 Linux 中应该是head。我不确定其他操作系统是否可以运行bash,并且headHEAD在某些操作系统中可能有效或无效,但head应该在任何地方都可以运行。
  • ls不建议解析。一篇关于它的文章。您遇到的问题是ls无法可靠地打印包含特殊字符或不可打印字符的名称。
  • 没有仅测试目录的逻辑,cd当没有目录时,您最终可能会尝试访问文件。
  • 没有逻辑来处理当前工作目录为空的情况。

除了解析问题之外,所有这些问题都可以调试ls。这是一个设计缺陷。如果你认为ls限制不会困扰你,那么你可以采用以下解决方案这是另一个答案

为了进行一些测试,您可以创建一个有问题的目录mkdir "$(echo -ne "foo\nbar")"ls如果这是目录,那么基于解决方案的解决方案可能会失败。要删除有问题的目录,请cdrc调用。cdrmdir "$(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被移动/重命名,则该函数将失败。如果函数运行时任何目录被移动/重命名,也可能会抛出错误。findstat

答案2

如果要包含所有目录,即以点开头

function cdrc { cd "$(ls -1atp|grep -v '^\.\.\?/$'|grep '/$'|head -1)"; }

否则就简单多了

function cdrc { cd "$(ls -1tp|grep '/$'|head -1)"; }

相关内容