#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/ParsingLs2. @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
-
разделенных токена. Быстрое, но непереносимое исправление, которое работает с GNUawk
и FreeBSD / OSXawk
(гдеlength()
может использоваться с массивами ):ls | awk -F '-' '{seen[$1,$2] } END { print length(seen) }'
. Переносимым, но менее эффективным решением является простой переход кwc -l
. Чтобы выполнить подсчет сам поawk
себе, см. Ответ @EdMorton. Замечания Эда об изучении идиом языка верны.