Рекурсивный поиск файлов с одинаковыми первыми 8 буквами

Цитировать документация gawk(добавлено примечание):

Any additional arguments on the command line are normally treated as input files to be processed in the order specified. However, an argument that has the form var=value, assigns the value value to the variable var—it does not specify a file at all.

Почему команда останавливается и ждет? Поскольку в формеawk 'processing_script_here' my=file.txtнет файла, указанного по приведенному выше определению,-my=file.txtинтерпретируется как присвоение переменной, и если файл не определен, awkбудет читать стандартный ввод (, что также видно из strace, который показывает, что awk в такой команде ожидает системного вызова read(0,'...).

Это также задокументировано в спецификациях POSIX awk ,см. раздел ОПЕРАНДЫ и назначения часть этого)

Присвоение переменной очевидно в awk '{print foo}' foo=bar /etc/passwd, где значение fooпечатается для каждой строки в /etc/passwd. Однако указание ./foo=barили полного пути работает.

Обратите внимание, что запуск straceна awk '1' foo=bar, а также проверка с помощью cat foo=barпоказывают, что это проблема, специфичная для awk -, и execve показывает имя файла в качестве переданного аргумента, поэтому оболочки не имеют ничего общего с переменной env. задания в этом случае.

Кроме того, обратите внимание, что awk '...script...' foo=barне приведет к созданию переменной среды оболочкой, поскольку назначение переменной среды должно предшествовать команде, чтобы она вступила в силу. См. Правила грамматики оболочки POSIX , пункт номер 7. Кроме того, это можно проверить с помощьюawk '{print ENVIRON["foo"]}' foo=bar /etc/passwd

0
13.03.2021, 23:26
2 ответа

Вы можете передать (должным образом отсортированный )список имен файлов через uniq -d. Предполагая, что ваша оболочка и uniqимеют одинаковые представления о порядке сортировки, например

printf -- "%s\n" * | cut -c1-8 | uniq -d

Если результат не -пустой, должны быть дубликаты. Обернув это в команду find:

find. -type d -exec sh -c '
  cd "$1" && test -n "$(printf -- "%s\n" * | cut -c1-8 | uniq -d)"
' find-sh {} \; -print

Так дано

$ tree.
.
├── subdir1
│   └── 20200403foo
├── subdir2
│   ├── 20200403bar
│   └── 20200403foo
├── subdir3
│   └── 20200403foo
├── subdir4
│   ├── 20200403bar
│   └── 20200403foo
└── subdir5
    └── 20200403foo

5 directories, 7 files

, затем

$ find. -type d -exec sh -c 'cd "$1" && test -n "$(printf -- "%s\n" * | cut -c1-8 | uniq -d)"' find-sh {} \; -print
./subdir4
./subdir2

Если вам нужно обрабатывать имена файлов, содержащие символы новой строки, а ваши cutи uniqподдерживают нулевые разделители, вы можете изменить конвейер на

printf "./%s\0" * | cut -zc1-10 | uniq -zd
3
18.03.2021, 22:25

Портативное решение, которое также правильно обрабатывает произвольные пути к файлам, в том числе содержащие символы новой строки, за счет некоторой степени неэлегантности и медлительности:

find /path/to/dir -type d \( -exec sh -c '
  cd "$1"
  printf "%s/" [0123456789][0123456789][0123456789][0123456789][01][0123456789][0123][0123456789]* \
    | awk -v RS="/" "seen[substr(\$0,1,8)]++ { exit 1 }"
  ' mysh {} \; -o -print \)

findиспользуется для рекурсивного поиска каталогов в /path/to/dirи в каждом найденном каталоге выполняется сценарий, который передает имена файлов, соответствующие шаблону, примерно напоминающему дату (предполагается формат гггг/мм/дд ), каждый из которых завершается символом /, в экземпляр awk, который читает/-отдельных записей и завершает работу со статусом 1, как только повторяется восьмисимвольный -символ (, начиная с первая строка )найдена во входных данных, в результате чего имя каталога будет -printed.

Более быстрая альтернатива, основанная на инструментах GNU:

find /path/to/dir -type f -name '[0123456789][0123456789][0123456789][0123456789][01][0123456789][0123][0123456789]*' \
  -print0 | awk -v FS='/' -v OFS='/' -v RS='\0' '
  { file=substr($NF,1,8); $NF=""; dir=$0 }
  seen[dir file]++ { dupl[dir] }
  END { for (d in dupl) print d }'

Здесь в /path/to/dirрекурсивно ищутся только обычные файлы, имя которых (примерно )начинается с даты. Найденные пути к файлам передаются в awkв виде потока записей, разделенных NUL -. Для каждой записи сохраняются только первые восемь символов последнего компонента (имени файла ), а результирующий путь сохраняется в ассоциативном массиве. При обнаружении дубликата распечатывается часть каталога (, т. е. путь с удаленным компонентом имени файла ).

0
18.03.2021, 22:25

Теги

Похожие вопросы