Подсчитывать файлы с уникальными префиксами

#awk

#awk

Вопрос:

У меня есть набор файлов, который выглядит следующим образом. Я ищу хороший способ подсчитать все файлы с уникальными префиксами, где «префикс» определяется всеми символами перед вторым дефисом.

 0406-0357-9.jpg   0591-0349-9.jpg   0603-3887-27.jpg  59762-1540-40.jpg 68180-517-6.jpg
0406-0357-90.jpg  0591-0349-90.jpg  0603-3887-28.jpg  59762-1540-41.jpg 68180-517-7.jpg
0406-0357-91.jpg  0591-0349-91.jpg  0603-3887-29.jpg  59762-1540-42.jpg 68180-517-8.jpg
0406-0357-92.jpg  0591-0349-92.jpg  0603-3887-3.jpg   59762-1540-5.jpg  68180-517-9.jpg
0406-0357-93.jpg  0591-0349-93.jpg  0603-3887-30.jpg  59762-1540-6.jpg
  

Комментарии:

1. как будет выглядеть результат для этого примера ввода?

2. ls | awk '{FS="-"}; /./{ if (a[$1$2] == 0) print $0;}'

3. @Jidder — эта команда awk содержит множество ошибок, а также является идиоматически неправильной. Проблемы, которые возникают: нет необходимости в точках с запятой, используйте условия в условии, а не в пространстве действий, не объединяйте поля для индекса массива, поскольку он завершается ошибкой на основе значений полей ( 12 3 и 1 23 оба объединяются 123 ), установка FS для каждой записи неэффективна и завершается ошибкой для первой записи (разделять перед установкой FS), нет необходимости печатать $ 0, поскольку это значение по умолчанию, проверять NF на наличие полей, которых нет /./, нет необходимости явно печатать вообще, если условие находится в нужном месте.

4. @Jidder И в целом, если вы даже не потрудились прочитать руководство, пожалуйста, не пытайтесь «помогать» людям.

5. @Jidder это работает! За исключением одной ошибки. Напишите это как ответ, и я приму. Вот ошибка: оба 0069-4210-0.jpg и 0069-4210-10.jpg печатаются.

Ответ №1:

В зависимости от того, что вы на самом деле хотите вывести, любой из них может быть тем, что вы хотите:

 ls | awk -F'-' '{c[$1"-"$2]  } END{for (p in c) print p, c[p]}'
  

или

 ls | awk -F'-' '!seen[$1,$2]  {count  } END{print count 0}'
  

Если это что-то другое, обновите свой вопрос, чтобы показать результат, который вы ищете.

Комментарии:

1. 1 Вероятно, хорошей идеей будет просто использовать awk вместо нескольких программ, как я это делал. Эй, стоит ли вообще указывать ls , как я сделал в своем ответе, чтобы убедиться, что псевдоним не используется? Или гарантируется, что псевдоним не будет использоваться, потому что он является частью конвейера? Очевидно ls , что в конвейере все немного по-другому, поскольку каждый файл отображается в отдельной строке. Но псевдоним ls -F все равно добавляет символ классификации.

2. Если вы собираетесь заключать в кавычки ls , то почему бы не заключать в кавычки и все остальные команды? Я бы не стал беспокоиться — ИМХО, вы больше рискуете использовать ls with . в своем PATH, чем ваш собственный псевдоним, сбивающий вас с толку.

3. Я понимаю, что вы не стали бы беспокоиться… кто бы это сделал? Это безумие! Но это проблема с псевдонимами. Если ls имеет псевдоним ls -F , и вам не нужны символы классификации, тогда вам в значительной степени придется заключать его в кавычки при вводе команды из командной строки. Другая возможность — поместить это в скрипт. Просто небольшая проблема, с которой я столкнулся некоторое время назад. Это заставило меня решить, что псевдонимы должны иметь имена, отличные от исходной команды.

4. Если cut присвоен псевдоним rm -rf / , вы тоже не хотите, чтобы это выполнялось, но кто это делает? В любом случае, все, что вам подходит….

5. 1, но к 1-му фрагменту относится обычное предостережение: перечисление [ассоциативных] ключей массива не сохранит порядок ввода.

Ответ №2:

Это должно сделать это:

 ls *.jpg | cut -d- -s -f1,2 | uniq | wc -l
  

Или, если ваши префиксы всегда состоят из 4 цифр, одного тире, 4 цифр, вам не нужно вырезать:

 ls *.jpg | uniq -w9 | wc -l
  

Комментарии:

1. Имейте в виду, что крайне не рекомендуется анализировать ls выходные данные mywiki. wooledge.org/ParsingLs

2. @Pankrates Я бы не сказал, что в данном случае это «сильно опрометчиво». Имена файлов кажутся довольно разумными.

3. Файлы не всегда состоят из четырех цифр, разделенных одним дефисом. например 59762-1540-42.jpg . Вот почему я хочу, чтобы все символы перед вторым дефисом были уникальными.

4. @RosePerrone В этом случае первый конвейер, который я дал, должен работать.

5. 1; если вы хотите избежать использования ls , попробуйте printf '%sn' *.jpg (не защитит от имен файлов со встроенными n символами., но это редко вызывает беспокойство в реальном мире).

Ответ №3:

Анализирует ls (плохо, но не похоже, что это вызовет проблемы с этими именами файлов), использует awk для установки разделителя полей как - .
!seen[$1,$2] ) использует ассоциативный массив с $1,$2 в качестве ключа и увеличивает, затем проверяет, равно ли значение 0, чтобы убедиться, что оно напечатано только один раз (на основе $1 и $2 ).
print выводит на экран 🙂

 ls | awk 'BEGIN{FS="-" ; printf("%-20s%-10sn","Prefix","Count")} {seen[$1"-"$2]  } END{ for (k in seen){printf("%-20s%-10in",k,seen[k])}}'
  

Теперь будет подсчитываться на основе префикса с заголовками 🙂

Комментарии:

1. Идиоматический awk для функционально эквивалентного решения будет ls | awk -F'-' '!seen[$1,$2] ' .

2. @EdMorton Это не code golf 🙂 Иногда лучше, чтобы код был легко читаемым 🙂

3. Нет, это не так, но в awk, как и в большинстве языков, есть идиомы, и использование массива с именем seen[] , как я показал, является одним из них (и не только в awk). Погуглите awk seen , и вы увидите множество примеров. Более краткий код не обязательно является худшим кодом, если он понятен (т.Е. Лаконичен, а не просто краток) и соответствует устоявшимся идиомам. Любой, кто знаком с awk, сразу поймет, что делает мой скрипт, а любой, кто этого не понимает, должен выучить идиому, поскольку она постоянно появляется.

4. Я не говорю, что это хуже или лучше, но я просто думаю, что код не нужно сокращать ради этого. Ваш код также будет печатать пустые строки (ну, одну), хотя я полагаю, что это не имеет значения при использовании ls. В любом случае, есть ли еще какие-либо проблемы с моим решением сейчас?

5. Многообещающе, но вы не подсчитываете результаты, вы просто печатаете первое имя файла из каждой группы имен файлов, разделяющих первые 2 - разделенных токена. Быстрое, но непереносимое исправление, которое работает с GNU awk и FreeBSD / OSX awk (где length() может использоваться с массивами ): ls | awk -F '-' '{seen[$1,$2] } END { print length(seen) }' . Переносимым, но менее эффективным решением является простой переход к wc -l . Чтобы выполнить подсчет сам по awk себе, см. Ответ @EdMorton. Замечания Эда об изучении идиом языка верны.