如何在每个父目录中打印最后一个目录

时间:2018-11-05 06:42:35

标签: linux shell perl unix

我有如下目录和子目录。

aaa/180809_1047
aaa/180915_0055
aaa/181012_1545
aaa/xyz
bbb/180809_1047
bbb/180915_0055
bbb/181012_1545
bbb/181105_0000
bbb/xyz
.
.
.
zzz/180821_1555
zzz/181004_2355
zzz/xyz

大多数子目录为YYMMDD_HHMM格式。在这里,我尝试从每个父目录中打印仅(最新)格式为YYMMDD_HHMM的子目录。以下是我的要求。

输出:

aaa/181012_1545
bbb/181105_0000
zzz/181004_2355

我使用了如下的find命令:

find ./*/ -type d -maxdepth 1 -mindepth 1 -name "???????????" | sort -u | tail -1

"???????????"->这将打印与YYMMDD_HHMM格式匹配的目录。

执行此命令后,我只会得到。

zzz/181004_2355 

4 个答案:

答案 0 :(得分:1)

我会使用for循环而不是使用find在bash中本地执行此操作。

老实说,我不记得bash是否对处理glob的顺序作出任何承诺。因此,使用包含的示例日期,这是一种使用[[比较文件的单行代码:

$ declare -A last=(); for a in *; do for b in $a/[0-9]*/; do [[ $b > $last[$a] ]] && last[$a]=$b; done; done; declare -p last
declare -A last=([bbb]="bbb/181105_0000/" [zzz]="zzz/181004_2355/" [aaa]="aaa/181012_1545/" )

请注意,此处的限制模式为$a/[0-9]*/,足以满足您的示例数据要求。当然,您可以使用字符类并消除glob来限制它。

还请注意,此模式中的结尾/可确保您仅匹配目录内容。这会将/放在$last数组中每个结果的末尾。您可以根据需要进行后处理:

$ for i in "${!last[@]}"; do last[$i]="${last[$i]%/}"; last[$i]="${last[$i]#*/}"; done
$ declare -p last
declare -A last=([bbb]="181105_0000" [zzz]="181004_2355" [aaa]="181012_1545" )

为便于阅读,这里将单线分割为多行。 :)

# Create an associative array. Requires bash 4+.
declare -A last=()

# Step through the top-level directories
for a in *; do
  # Step through the second level directories
  for b in "$a"/[0-9]*/; do
    # Compare and record as required
    [[ $b > $last[$a] ]] && last[$a]="$b"
  done
done

# Print the result
declare -p last

答案 1 :(得分:0)

您将使用tail -1尾随命令的输出。因此,您只会得到最后一行。 :)

除了您的命令看起来正确之外。

加上其他注释:

  1. 您可以编写find .而不会出现全局错误,因为默认情况下find是递归的
  2. 如果需要,
  3. ???????????可能会更具限制性。选择??????_????或使用[[:digit:]]

答案 2 :(得分:0)

使用sort -utail -1的想法很好,并且与同一个父目录中的子目录列表一起使用时,它会起作用。 -u将删除重复项,但这不是必需的,因为2个子目录在同一父目录中不能具有相同的名称。

?表示任何字符;可以使用限制性更强的[0-9]来选择一个数字。

尝试一下:

find . -maxdepth 1 -type d  -print0 | xargs -0 sh -c '
 for dir ; do 
   find "${dir}" -maxdepth 1 -type d \
    -name '[0-9][0-9][0-1][0-9][0-3][0-9]_[0-2][0-9][0-6][0-9]' | sort | tail -1
 done' dummy | sort

对于在第一级(第一个find . -maxdepth 1 ...)中找到的每个目录:

  • 所有与模式匹配的子目录 列出了[0-9][0-9][0-1][0-9][0-3][0-9]_[0-2][0-9][0-6][0-9](第二find
  • 仅打印最新版本(感谢sorttail命令)

-print0-0参数与sh -cfor statement一起使用,以使命令行对带有特殊字符(例如{{1 }}。

line break未使用,但它是强制性的,请参见dummy

测试

man sh

答案 3 :(得分:0)

使用查找,排序和awk:

find -name '??????_????' -type d | sort -r | awk -F'/' '{if(!s[$(NF-1)]++) print $0}