awk соответствует только первой строке при сравнении с первым столбцом - PullRequest
0 голосов
/ 13 февраля 2020

Со следующим файлом debug.txt :

a,b,1
a,b,2
a,b,3
a,b,4
a,b,5

Это печатает третий столбец только первой строки:

$ awk -F ',' '$1 == "a" {print($3)}' debug.txt 
1

, в то время как это печатает третий столбец всех 5 строк:

$ awk -F ',' '$2 == "b" {print($3)}' debug.txt 
1
2
3
4
5

Почему это? И как бы выбрать все строки, где первый столбец соответствует a?

РЕДАКТИРОВАТЬ: Вот двоичный вывод debug.txt :

$ cat -v debug.txt 
a,b,1
^Ma,b,2
^Ma,b,3
^Ma,b,4
^Ma,b,5
$ hexdump -Cv debug.txt
00000000  61 2c 62 2c 31 0a 0d 61  2c 62 2c 32 0a 0d 61 2c  |a,b,1..a,b,2..a,|
00000010  62 2c 33 0a 0d 61 2c 62  2c 34 0a 0d 61 2c 62 2c  |b,3..a,b,4..a,b,|
00000020  35                                                |5|
00000021
$ file debug.txt
debug.txt: ASCII text, with CR, LF line terminators

Обратите внимание, что 5 - последний символ в файле (без завершающей строки).

1 Ответ

1 голос
/ 14 февраля 2020

TL; DR:

Символ возврата каретки (CR или \r) приводит к тому, что awk соответствует ^Ma для первого столбца, в результате чего $1 == "a" становится ложным для всех, кроме первая строка.

Объяснение

Происходит следующее: debug.txt имеет некоторые странные символы новой строки. В конце каждой строки есть эта последовательность: 0x0a0d (которая отображается в виде новой строки, а затем ^M с cat -v debug.txt).

Статья Википедии для новой строки указывает, что Новые строки Unix / Linux - это просто 0xa (\n или LF), а новые Windows - 0x0d0a (\r\n или CRLF). Каким-то образом debug.txt имеет «задом наперед» Windows переводы строки - 0x0a0d (\n\r или LFCR). Это является причиной всех неприятностей.

awk достаточно умен, чтобы справиться с обычной новой строкой Windows, когда видит CRLF. Однако, когда он видит LFCR в конце первой строки, он предполагает, что это обычный Unix символ новой строки, за которым следует отдельный возврат каретки.

Поскольку CR теперь находится на следующей строке, когда awk разделяет первый столбец следующей строки, он правильно видит его как ^Ma вместо a. Таким образом, $1 == "a" оценивается как "^Ma" == "a", что неверно. Поэтому все строки, кроме первой, игнорируются.

Примеры

Следующие файлы имеют то же содержимое, что и debug.txt , за исключением того, что строки заканчиваются на 0x0a0d (LF + CR), 0x0d0a (CR + LF) и 0xa (LF) соответственно ( debug.txt и debug-lfcr.txt одинаковы) :

$ cat -v debug-lfcr.txt 
a,b,1
^Ma,b,2
^Ma,b,3
^Ma,b,4
^Ma,b,5
$ awk -F ',' '($1 == "a") {print($3)}' debug-lfcr.txt 
1
$ cat -v debug-crlf.txt 
a,b,1^M
a,b,2^M
a,b,3^M
a,b,4^M
a,b,5
$ awk -F ',' '($1 == "a") {print($3)}' debug-crlf.txt 
1
2
3
4
5
$ cat -v debug-lf.txt 
a,b,1
a,b,2
a,b,3
a,b,4
a,b,5
$ awk -F ',' '($1 == "a") {print($3)}' debug-lf.txt 
1
2
3
4
5

Как исправить файлы

Таким образом, решение состоит в том, чтобы заменить все последовательности LFCR на CRLF или LF .

Чтобы преобразовать только в LF из LFCR, удалите все CR:

tr -d '\r' < debug.txt > debug-cured.txt

Чтобы преобразовать в CRLF из LFCR, удалите CR и добавьте их обратно в конец каждая строка:

tr -d '\r' < debug.txt | sed -e '$a\' | sed 's/$/\r/' > debug-cured.txt

(| sed -e '$a\' является необязательной - она ​​просто добавляет новую строку в конец файла, если это еще не сделано. Это позволяет избежать окончания файла с помощью автономного CR, который может вызвать проблемы позже).

См. Удалить возврат каретки в Unix, Добавить текст в конце каждой строки и https://unix.stackexchange.com/questions/31947/how-to-add-a-newline-to-the-end-of-a-file.

Помимо

Причина появления новых строк LFCR заключается в том, что я имел дело с программным обеспечением, которое выводило текст на виртуальную консоль и на аппаратный UART. Эта специальная c функция печати программного обеспечения будет обнаруживать НЧ в тексте и вводить CR после . Аппаратному UART нужны как LF, так и CR, но порядок не имеет значения. Таким образом, программное обеспечение выбрало LFCR, поскольку его реализация несколько быстрее, чем CRLF.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...