Соедините строку, заканчивающуюся обратной косой чертой, со следующей строкой awk (из известных однострочных строк awk, объясненных)

#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 , что автоматически приводит к добавлению следующей команды вывода в ту же строку вывода.