我想通过终端打开一个随机选择的文件。我发现shuf
,这似乎正是我需要的实用程序,尽管我无法找到一种方法来使我正在使用的命令递归。
最初我使用了open $(ls | gshuf -n1)
,如果我有一个平面目录结构,它效果很好。我怎样才能让它递归到任意数量的子目录并过滤掉像.DS_Store
和 这样的文件?
答案1
正确的工具是find
。它以递归方式工作,这解决了您的主要问题。如果您知道如何操作,您可以排除各种模式。
基本用法如下:
open "$(find . -type f | shuf -n1)"
文件名中的换行符会破坏这一点。您的工具可能支持或不支持允许传递 NUL 终止数据的非 POSIX 选项。此代码片段在我的 Debian 中有效:
find . -type f -print0 | shuf -z -n1
尽管如果你将其嵌入$(…)
,尾随换行符(如果有)仍将被删除。
要排除名称,您可以使用类似的语法! -name .DS_Store
,但要排除整个子目录,您需要-prune
. 存在陷阱:
- 操作数的顺序很重要,例如,
-prune
目录应该在之前-type f
,-print
/-print0
通常位于最后。 - 逻辑“或” (
-o
)通常需要括号而且它并不像你希望的那样直观。 - 省略
-print
/-print0
可能会产生超出预期的结果。对于复杂的逻辑,最好明确包含-print
/-print0
。
学习man 1 find
以了解更多信息。这是一个排除两个目录和两个名称模式的工作示例:
find . \( -name dir1 -o -name "dir 2" \) -prune -o -type f ! \( -name "*.txt" -o -name "echo*" \) -print
既然你需要$(…)
并且我告诉你要正确引用,你应该知道里面的引号$(…)
是单独解析的。例如,这是正确的引用:
open "$(find . -type f ! -name "not this file" | shuf -n1)"
(比较这个答案,怪癖2)。