#linux #unix
Вопрос:
Это упражнение взято из однострочного сообщения в блоге AWK, которое объяснил Петерис Круминьш
По сути, эта строка
awk '/\$/ { sub(/\$/,""); getline t; print $0 t; next }; 1'
соединяет каждую строку, заканчивающуюся обратной косой чертой, со следующей строкой:
например, ввод
12345
6789
523435
00000
Выход
123456789
52343500000
В сообщении в блоге говорится:
К сожалению, этот один лайнер не может соединить более 2 строк (это оставлено в качестве упражнения для читателя, чтобы придумать однострочный, который соединяет произвольное количество строк, заканчивающихся обратной косой чертой :)).
Таким образом, использование однострочной строки AWK выше, и если вы используете входной файл с 2 или более строками одна за другой, в конце которого есть обратная косая черта (input2), дает неправильный ответ (output2), например, input2
12345
6789
523435
00000
Вывод 2 — НЕВЕРНЫЙ
123456789
52343500000
Я думаю, что, согласно сообщению, вместо вывода должен быть вывод3:
Вывод 3 — ПРАВИЛЬНЫЙ
12345678952343500000
Как можно решить эту проблему (ввод как ввод2 и получение вывода 3)?
Комментарии:
1. Не делайте
awk '/\$/ { sub(/\$/,""); getline t; print $0 t; next }; 1'
этого , это неправильный подход и может потерпеть неудачу различными способами.
Ответ №1:
Попробуйте сделать следующее:
awk '/\$/ { printf "%s", substr($0, 1, length($0)-1); next } 1' <<'EOF'
12345
6789
523435
00000
EOF
что дает
12345678952343500000
Это демонстрирует, что 3 последовательных (или более) продолжения строк работают нормально, в отличие от команды в вопросе.
Объяснение команды:
/\$/
соответствует a$
) строки, сигнализируя о продолжении строки.substr($0, 1, length($0)-1)
удаляет этот конец$0
.- При использовании
printf "%s"
(измененная) текущая строка печатается без конечной новой строки , что означает, что любая следующая команда печати будет непосредственно добавлена к ней, эффективно соединяя текущую и следующую строки. next
завершает обработку текущей строки.1
это распространеннаяawk
идиома , которая является сокращением{ print }
, т. Е. для простой печати входной строки (сn
завершением ).
Что касается того, почему исходная команда не работает:
awk '/\$/ { sub(/\$/,""); getline t; print $0 t; next }; 1
- При обнаружении символа продолжения строки (
getline t
считывает следующую строку из файла и печатает ее как есть после текущей строки. next
затем завершает обработку как текущей, так и — благодаряgetline
вызову — следующей строки, так что следующий цикл скрипта обрабатывает строку после следующей строки (2 строки от текущей).- Поэтому, поскольку строка, прочитанная с помощью
getline
, печатается вслепую и никоим образом не проверяется, она пропускается в отношении обработки символов продолжения строки.
В целом, как отмечает Эд Мортон в комментарии, использование getline
редко является правильным решением и может привести к незначительным ошибкам — см. http://awk.info/?tip/getline.
Комментарии:
1. Что делать, если в последней строке есть обратная косая черта?
2. Спасибо, хотя я все еще немного не понимаю, как хранится ответ от одной итерации к другой? Обычно должно быть что-то вроде lineSoFar=lineSoFar (объединить с) измененной линией? (надеюсь, это имеет смысл).
3. массивы и строки awk начинаются с индекса 1, а не с 0.
substr($0,0,...)
делает только то, что вы хотите, потому что приsubstr()
обнаружении недопустимого индекса, например0
, 2-го аргумента, по умолчанию используется значение по1
умолчанию. Воспользуйсяsubstr($0,1,...)
.4. Спасибо, @EdMorton; исправлено.
5.@SonicProtein: Пожалуйста, посмотрите на 3-й пункт в объяснении. Перефразируя это: ничто не сохраняется в разных строках; вместо этого, когда встречается строка, заканчивающаяся на
, используется
printf
безn
, что автоматически приводит к добавлению следующей команды вывода в ту же строку вывода.