我有这个命令对我有用,它会在当前目录中找到与模式匹配的零个或一个目录:
find . -maxdepth 1 -type d -name 'suman-*'| head -n1
在MacOS上,这将导致类似:
./suman-1479860474833
<!EDIT>
我的目标是找到最新的目录(具有最新的时间戳)。目录内容如下所示:
foo
bar
baz
suman-1479860475524
suman-1479860471431
suman-1479860474233
...
etc.
</EDIT>
我有三个问题,
使用bash,如果结果中存在./
字符,如何删除它们?他们应该永远在那里,但我想总是删除
前两个字符可能太卡利了。
使用bash,而不是使用head
查找第一个结果,找到最后结果的最佳方法是什么?我猜它是tail
,但也许在那里
是一种更好的方式。
有没有办法只匹配一个数字而不只是使用'suman-*'
?也许我应该使用-regex
代替-name
?
现在,我可以按目录名称中的时间戳对目录进行排序,或者我可以按其元数据对它们进行排序(如果元数据准确并且通过版本控制更新等持续存在)。我个人并不确定目录元数据是否足够持久,所以我想更加透明并使用目录名中的时间戳。 和看起来在Unix中没有为目录创建时间=&gt; &#34;在Unix中,创建时间不存储(仅限:访问,修改和更改)。&#34;
答案 0 :(得分:2)
使用GNU find
,如果您不想./
,则可以简单地避免告诉find
打印它。
# with GNU find
find . -maxdepth 1 -type d -name 'suman-*' -printf '%P\n' | head -n1
%P
格式字符串排除了从find
的参数派生的文件名部分 - 在本例中为./
。
使用BSD find
,你没有这个选项,但是一旦你的结果出现在shell变量中就可以进行后处理:
# strip "./" prefix from filename variable, if and only if it exists
filename=${filename#./}
至于head
或tail
,订购无法保证,因此您无法依赖此类选项来查找特定文件。如果您想要最新,最旧,第一,最后等,那么您需要做一些额外的工作才能以可靠的方式实现这一目标。例如:
IFS= read -r -d '' filename \
< <(find . -maxdepth 1 -type d -name 'suman-*' -printf '%P\0' | sort -z)
...将在流排序时读取第一个项目,并且......
IFS= read -r -d '' filename \
< <(find . -maxdepth 1 -type d -name 'suman-*' -printf '%P\0' | sort -rz)
...将按相反方向排序,从而读取最后的内容。
请注意,find -print0
或sort -z
都没有指定POSIX,但这两者在GNU工具链和当前MacOS中均可用。相比之下,find -printf
需要GNU查找;这可以通过macports findutils
包安装在MacOS上(将其安装为gfind
)
答案 1 :(得分:2)
stat -f "%HT %Sm %i" -t %Y%m%d%H%M%S * | grep "^Directory" | cut -f2- -d ' ' | sort -rn | head -1 | cut -f2- -d ' ' | while read inode ; do find . -inum "$inode" | basename "$(cat -)" ; done
结果:suman-1479860475524
suman-
时间戳(OS X兼容):
find ./ -mindepth 1 -maxdepth 1 -type d -name "suman-*" -print0 | sort -zn | while IFS= read -d '' file ; do basename "$file" ; done | tail -1
结果:
suman-1479860475524
最近的文件夹(任何名称):
stat -f "%HT %Sm %i" -t %Y%m%d%H%M%S *
:列出以机器可读时间戳开头的文件夹(以秒为单位(因此cut
可以安全使用),并显示类型,阳极和时间戳(见https://www.freebsd.org/cgi/man.cgi?stat(1)):
Directory 20161124051357 17658795 Directory 20161124051358 17658796 Directory 20161124051356 17658793 Directory 20161124051359 17658798 Directory 20161124051400 17658800 Directory 20161124051401 17658802
| grep "^Directory" | cut -f2- -d ' '
:选择文件夹,并修剪“目录”
| sort -rn
:数字排序,最新到最早
| head -1
:仅限最近的
| cut -f2- -d ' '
:仅显示inode组件
| while read inode ; do find . -inum "$inode" -print0
:根据inode查找文件(有些人可能会认为此步骤不是必需的,但如果包含特殊字符的奇怪命名文件夹,它会返回完整的文件夹名称)
此时(如果我们在这里添加了; done
),我们会:
./suman-1479860475524
最后
| basename "$(cat -)" ; done
:只返回文件夹的名称:
suman-1479860475524
最近的suman-
文件夹时间戳:
find ./ -mindepth 1 -maxdepth 1 -type d -name "suman-*" -print0
:获取当前文件夹中的文件夹名称
| sort -zn
:根据目录名称中的时间戳,而不是实际的文件系统修改时间戳,对它们进行数字排序。
while IFS= read -d '' file ; do basename "$file" ; done
:从文件中删除目录位置字符和斜杠,并将文件列表输出为行分隔
| tail -1
:只列出最新的一个。
在此示例中,结果恰好相同:
suman-1479860475524
...while read inode ;
...变得有用的奇数文件夹名称示例:
<强> 1 强>
mkdir $'some \r\t strange \n folder \n\n name \n totally nuts'
<强> 2 强>
stat -f "%HT %Sm %i" -t %Y%m%d%H%M%S * | grep "^Directory" | cut -f2- -d ' ' | sort -rn | head -1 | cut -f2- -d ' ' | while read inode ; do find . -inum "$inode" -print0 | basename "$(cat -)" ; done
3. (输出)
some strange folder name totally nuts
使用bash,我怎样才能删除./字符,如果它们存在于 结果? (希望他们永远在那里,但我想永远 删除前两个字符可能太过分了。)
basename
find "$PWD"
代替find .
(这将生成完整路径)-printf "%P"
(这只显示没有./
的名称部分)(注意: -printf
需要GNU查找 )使用bash,而不是找到头部的第一个结果是什么 找到最后结果的最好方法(我猜它是尾巴,但也许 有更好的方法)
一种方法是使用:
find ... | sort -n | tail -n1
find ... | sort -rn | tail -n1
(显然“First”可能实际上是“Last”,具体取决于它对你的意义。你可以基本上用head
命令代替这个事实,只要你保持一致,-r
在sort
中将反转顺序,因此两个管道命令集将为您提供“第一个”和“最后”结果)
有没有办法只匹配一个数字(这是一个时间戳) millis)而不是只使用'suman- *'?也许我应该使用-regex 而不是-name?
您可以-name '*1479860474833'
代替-name 'suman-*'
此示例的三个测试文件夹:
示例1:
这是一个严格的例子,可以减少使用嵌入式特殊字符的疯狂文件夹名称的风险
find "$PWD" -mindepth 1 -maxdepth 1 -type d -print0 | sort -zn | tail -zn1
给出:
/my/dir/suman-1499860474833
示例2:
使用printf
和\0
删除前导“./”,同时保持NULL分隔:
find "$PWD" -mindepth 1 -maxdepth 1 -type d -printf "%P \0" | sort -zn | tail -zn1
给出:
suman-1499860474833
注意:-mindepth 1
可以避免返回父文件夹。
答案 2 :(得分:1)
<强> TL;博士强>
printf '%s\n' suman-*/ | tail -n 1 | sed 's|/$||' # ... | cut -d/ -f1 works too
请注意,此答案假设文件名没有嵌入的换行符,幸运的是,这很少是现实世界的关注。
除非另有说明,否则本答案中的所有命令均符合POSIX标准。
如果您只在目标目录中查找直接子目录,那么就不需要find
- 一个简单的 glob 会这样做:
printf '%s\n' suman-*/ | head -n 1
但请注意:
/
。suman-*/
,根据定义,它永远不会与隐藏的目录匹配。) - 包含一般的隐藏项目,首先运行shopt -s dotglob
(这是 Bash 扩展名)。printf
输出传递给{{在进一步处理之前1}}或sort -f
。关于查找与模式匹配的最近 modified 目录的请求,将sort -rf
与glob组合是最简单的选项:
ls -dt
相反,如果目录名中嵌入的时间戳应该驱动排序(例如ls -dt suman-*/ | head -n 1 # print most recently modified suman-* subdir.
),反向词法排序将会:< / p>
1479860475524
没有尾随ls -dr suman-*/ | head -n 1
:
/
稍微繁琐,但更强大的替代,避免使用ls -dr suman-*/ | head -n 1 | sed 's|/$||' # with no path prefix, | cut -d/ -f1 works too
来支持避免最大值。调用外部实用程序时的命令行长度,如ls
所报告的那样,如果大量文件与glob匹配则可能会引起关注:帽子提示{{1} 3}}
getconf ARG_MAX
注意:这假定printf '%s\n' suman-*/ | tail -n 1 | sed 's|/$||'
是作为 shell builtin 实现的(而不是必须依赖printf
实用程序),但是,对于所有类似POSIX的主要shell(printf
,bash
,zsh
,ksh
)都是如此。
使用dash
的不区分大小写的替代方案(在此方案中没有任何区别):
sort
关于你的3个原始问题:
重新1):使用printf '%s\n' suman-*/ | sort -rf | head -n 1 | sed 's|/$||'
修剪尾随sed
:/
(如果剥离路径前缀也是一个问题,它最容易printf '%s\n' suman-*/ | head -n 1 | sed 's|/$||'
首先是路径前缀,然后使用仅文件名的glob。。
Re 2):使用cd
获取词汇最后一个条目(或printf ... | tail -1 | ...
以获得词汇最后一个条目,无论情况如何)。
Re 3):( globbing)模式允许每个字符位置的数字与printf ... | sort -rf | head -n 1 | ...
等字符集匹配,但是你不能应用正则表达式的量词(重复符号),例如[0-9]
和?
给他们。
一般来说,使用+
和globbing / find
之间存在许多微妙的差异 - 警告。
通常,Charles Duffy,但是 - 假设有人知道边缘情况和限制 - 有时这是最方便的解决方案。
答案 3 :(得分:0)
认为&#34;更简单更好&#34;:
# 1: Using cut (The option "-c 3-" means "from 3rd character"
find... | cut -c 3-
# 2: You're right, tail is the command (-n1 == -1)
find... | tail -1
# 3: -name should do it:
TIME=1479860474833
find... -name "suman-$TIME"
编辑:
正如你所说:
目录内容如下:
foo bar baz suman-1479860475524 suman-1479860471431 suman-1479860474233 ... etc.
最近
要根据名称获取最新目录,您可以执行以下操作:
$ find . -maxdepth 1 -type d -name suman-\* | cut -c3- | sort -rnk1.7 | head -1
# Result is:
suman-1479860475524
如果内容只有名称如&#39; suman *&#39; (从来没有具有该模式的文件),那么我认为这更容易:
$ ls -1d suman-* | sort -rnk1.7 | head -1
# Result is:
suman-1479860475524
在这两种情况下,排序选项-r
(反向)带来最新的第一个,-k1.7
将从第7个字符(名称的毫秒部分)中按数字-n
排序。
<强>最旧强>
为了获取最旧的目录,根据名称,不要使用-r
选项:
$ find . -maxdepth 1 -type d -name suman-\* | cut -c3- | sort -nk1.7 | head -1
# Result is:
suman-1479860471431
$ ls -1d suman-* | sort -nk1.7 | head -1
# Result is:
suman-1479860471431