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.