Как напечатать последний каталог внутри каждого родительского каталога - PullRequest
0 голосов
/ 05 ноября 2018

У меня есть набор каталогов и подкаталогов, как показано ниже.

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 ./*/ -type d -maxdepth 1 -mindepth 1 -name "???????????" | sort -u | tail -1

"???????????" -> для печати каталогов, соответствующих формату YYMMDD_HHMM.

После этой команды я получаю только.

zzz/181004_2355 

Ответы [ 4 ]

0 голосов
/ 05 ноября 2018

Используя find, sort, awk:

find -name '??????_????' -type d | sort -r | awk -F'/' '{if(!s[$(NF-1)]++) print $0}
0 голосов
/ 05 ноября 2018

Я бы сделал это изначально в bash, используя цикл for, а не find.

Я, честно говоря, не могу вспомнить, дает ли bash какие-либо обещания о порядке обработки глобусов. Итак, используя указанную вами дату выборки, приведем однострочное сравнение файлов, используя [[:

$ 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]*/, что достаточно для ваших данных выборки. Конечно, вы можете ограничить это по мере необходимости, используя классы символов и устраняя глобус.

Обратите также внимание, что конечный / в этом шаблоне гарантирует, что вы будете сопоставлять только то, что является каталогами. Это поместит / в конце каждого результата в массиве $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
0 голосов
/ 05 ноября 2018

Идея использовать sort -u и tail -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)
  • печатается только самая последняя версия (спасибо sort и tail команды)

аргументы -print0 и -0 используются вместе с sh -c и for statement для обеспечения устойчивости командной строки к именам файлов со специальными символами, такими как line break.

dummy не используется, но является обязательным, см. man sh

TEST

mkdir -p aaa/180809_1047 aaa/180915_0055 aaa/181012_1545 aaa/xyz \
bbb/xyz bbb/180809_1047 bbb/180915_0055 bbb/181012_1545 bbb/181105_0000 \
zzz/xyz zzz/180821_1555 zzz/181004_2355

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


./bbb/181105_0000
./aaa/181012_1545
./zzz/181004_2355
0 голосов
/ 05 ноября 2018

Вы выводите команду с помощью tail -1. Таким образом, вы получите только самую последнюю строку. :)

Кроме того, ваша команда выглядит правильно.

Пара других заметок:

  1. Вы можете написать find . без глобуса, потому что поиск по умолчанию рекурсивен
  2. ??????????? может быть более ограничительным, если вам нужно. ??????_???? или использование [[:digit:]] будут возможными вариантами.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...