Чтобы выполнить сортировку по двум полям, необходимо сообщить sort, что это такое и как их сортировать; например:
sort -k1,1nr -k2b < input
сортирует по полю 1(-k1,1
)численно в обратном (убывающем )порядке; для строк, где поле 1 равно, вторичная сортировка по остальной части строки(-k2
)обычно (лексически )без начальных пробелов (интервал между первым и вторым полем )в ключе сортировки(b
). Вывод на вашем примере ввода:
4 alice
4 bottle
4 came
4 sure
4 window
3 began
3 little
3 moment
3 rabbit
3 thing
3 till
2 went
2 wonder
2 wont
В качестве альтернативы, используя grep
и предполагая, что ни sed
, ни grep
не могут быть использованы и что у вас есть тысячи файлов, каждый из которых содержит тысяч строк, так что вы хотите проверить только самую первую строку каждого, а не grep
пинговать их полностью.....
Возьмите все первые строки (с именем файла )и закиньте их в файл
head -n1 *.csv > list
Каждая запись имеет одну строку контекста (имя файла ), первую строку и пустую строку после, например
==> a.csv <==
1234567,11111111111111111111111111111111111111111111111111
==> b.csv <==
1234567845610111211111111111111111111111111
Вы знаете, что шаблон для согласования строк — это ^[0-9.]+,[0-9.]+$
, поэтому вы можете
grep -E -B1 "^[0-9]+,[0-9]+$" list | grep -oP "(?<= )[^, <]+" > ok.list
Первый grep
извлекает совпадения из list
с одной строкой контекста перед-B1
(именем файла, содержащим совпадение ), а второй удаляет имена файлов и выгружает их в нужный файлok.list
Наконец, вы можете использовать ok.list
для фильтрации
ls *.csv | grep -Fvxf ok.list > banjaxed.list
Где вы просто используете grep
для фильтрации файлов в ok.list
из файлов из ls
с фиксированными строками (не регулярное выражение )'-F', только точные совпадения -x
используя файлы -f
как список шаблонов для сопоставления и, конечно же, инвертируя -v
совпадение, окончательно перенаправляя отфильтрованный список наbanjaxed.list
Если это не стоит хоть чего-то, то я пакую свои игрушки.
Если я правильно понимаю, что вы хотите удалить любой файл, содержащий любую строку, в которой верно любое из следующих утверждений:
!$1
!$2
NF!=2
Тогда
awk -F',' 'BEGINFILE{ok=1}!$1||!$2||NF!=2{ok=0; nextfile}ENDFILE{if (ok) print FILENAME}' *.csv
Который просто устанавливает флаг ok=1
, а затем выполняет цикл по каждой строке до тех пор, пока любое из вышеуказанных условий не будет истинным, и, как только он находит «плохую» строку, делает файл недействительным с помощью ok=0
и пропускает до конца файл без разбора дополнительных строк nextfile
.
В конце каждого файла ENDFILE
он печатает FILENAME
только тогда, когда if (ok)
не равно -нулю
Таким образом, чтобы отменить совпадение, просто инвертируйте последний тест на if (!ok)
для печати
awk -F',' 'BEGINFILE{ok=1}!$1||!$2||NF!=2{ok=0; nextfile}ENDFILE{if (!ok) print FILENAME}' *.csv
Редактировать
Я не могу воспроизвести сбой вывода на своемgawk
(см. ниже, включая перенаправление имен файлов в xxx.file)
bash --version
GNU bash, version 5.0.16(1)-release (x86_64-pc-linux-gnu)
awk --version
GNU Awk 5.1.0, API: 3.0 (GNU MPFR 4.0.2, GNU MP 6.2.0)
tail -n +1 *.csv;
awk -F',' 'BEGINFILE{ok=1}
!$1||!$2||NF!=2{ok=0; nextfile}
ENDFILE{gzout=(ok)?"ok":"banjaxed"; print FILENAME > gzout".files"}' *.csv ;
tail -n +1 *.files
==> a.csv <==
1234567,11111111111111111111111111111111111111111111111111
==> b.csv <==
1234567845610111211111111111111111111111111
==> c.csv <==
111111,22222222,3333333,,,44444444444444444444
==> banjaxed.files <==
b.csv
c.csv
==> ok.files <==
a.csv
Ограничения длины отдельных полей (1024)не должны быть проблемой для awk
, если только вы не превысите ограничение в 3000 символов, и в этом случае ни awk
, ни sed
не кажутся инструменты для работы.