Как объединить все две строки в одну из командной строки?

У меня есть текстовый файл со следующим форматом. Первая строка - "КЛЮЧ", а вторая строка - "VALUE".

KEY 4048:1736 string
3
KEY 0:1772 string
1
KEY 4192:1349 string
1
KEY 7329:2407 string
2
KEY 0:1774 string
1

Мне нужно значение в той же строке, что и ключ. Таким образом, результат должен выглядеть следующим образом:

KEY 4048:1736 string 3
KEY 0:1772 string 1
KEY 4192:1349 string 1
KEY 7329:2407 string 2
KEY 0:1774 string 1

Лучше, если бы я использовал некоторый разделитель, например $ или ,:

KEY 4048:1736 string , 3

Как объединить две строки в одну?

Ответ 1

AWK:

awk 'NR%2{printf "%s ",$0;next;}1' yourFile

Заметьте, что в конце вывода есть пустая строка.

СЭД:

sed 'N;s/\n/ /' yourFile

Ответ 2

paste подходит для этой работы:

paste -d " "  - - < filename

Ответ 3

Альтернатива sed, awk, grep:

xargs -n2 -d'\n'

Это лучше всего, когда вы хотите присоединиться к N строкам, и вам нужен только объемный вывод.

Мой первоначальный ответ был xargs -n2, который отделяется от слов, а не от строк. -d может использоваться для разделения ввода на любой отдельный символ.

Ответ 4

Есть больше способов убить собаку, чем повешение. [1]

awk '{key=$0; getline; print key ", " $0;}'

Поместите любой разделитель в кавычки.


Литература:

  • Первоначально "Множество способов скинуть кошку", вернулось к более старому, потенциально происходящему выражению, которое также не имеет ничего общего с домашними животными.

Ответ 5

Хотя кажется, что предыдущие решения будут работать, если в документе возникнет одна аномалия, вывод будет разложен. Ниже немного безопаснее.

sed -n '/KEY/{
N
s/\n/ /p
}' somefile.txt

Ответ 6

Вот еще один способ с awk:

awk 'ORS=NR%2?FS:RS' file

$ cat file
KEY 4048:1736 string
3
KEY 0:1772 string
1
KEY 4192:1349 string
1
KEY 7329:2407 string
2
KEY 0:1774 string
1

$ awk 'ORS=NR%2?FS:RS' file
KEY 4048:1736 string 3
KEY 0:1772 string 1
KEY 4192:1349 string 1
KEY 7329:2407 string 2
KEY 0:1774 string 1

Как указано Эд Мортон в комментариях, лучше добавить фигурные скобки для безопасности и parens для переносимости.

awk '{ ORS = (NR%2 ? FS : RS) } 1' file

ORS обозначает выходной разделитель записи. Мы здесь тестируем условие, используя NR, который хранит номер строки. Если по модулю NR - истинное значение ( > 0), мы устанавливаем разделитель полей вывода на значение FS (полевой разделитель), который по умолчанию является пространством, иначе мы присваиваем значение RS (Запись Separator), который является новой линией.

Если вы хотите добавить , в качестве разделителя, используйте следующее:

awk '{ ORS = (NR%2 ? "," : RS) } 1' file

Ответ 7

Вот мое решение в bash:

while read line1; do read line2; echo "$line1, $line2"; done < data.txt

Ответ 8

"ex" - это редактор сценариев, который находится в том же семействе, что и sed, awk, grep и т.д. Я думаю, это может быть то, что вы ищете. Многие современные vi-клоны/преемники vi также имеют режим vi.

 ex -c "%g/KEY/j" -c "wq" data.txt

Это говорит для каждой строки, если она соответствует "KEY", выполните команду j в следующей строке. После завершения этой команды (против всех строк) выполните обход w и q uit.

Ответ 9

Вы можете использовать awk, чтобы объединить все две пары строк:

awk '{ if (NR%2 != 0) line=$0; else {printf("%s %s\n", line, $0); line="";} } \
     END {if (length(line)) print line;}' flle

Ответ 10

Если параметр Perl является опцией, вы можете попробовать:

perl -0pe 's/(.*)\n(.*)\n/$1 $2\n/g' file.txt

Ответ 11

Вы также можете использовать следующую команду vi:

:%g/.*/j

Ответ 12

Небольшое отклонение от glenn jackman answer с помощью paste: если значение для параметра -d delimiter содержит более одного символа, paste циклически проходит символы один за другим и в сочетании с параметрами -s продолжают делать это при обработке одного и того же входного файла.

Это означает, что мы можем использовать все, что хотим, в качестве разделителя плюс escape-последовательность \n, чтобы объединить две строки за раз.

Использование запятой:

$ paste -s -d ',\n' infile
KEY 4048:1736 string,3
KEY 0:1772 string,1
KEY 4192:1349 string,1
KEY 7329:2407 string,2
KEY 0:1774 string,1

и знак доллара:

$ paste -s -d '$\n' infile
KEY 4048:1736 string$3
KEY 0:1772 string$1
KEY 4192:1349 string$1
KEY 7329:2407 string$2
KEY 0:1774 string$1

То, что это не может сделать, это использовать разделитель, состоящий из нескольких символов.

В качестве бонуса, если paste совместим с POSIX, это не изменит новую строку последней строки в файле, поэтому для входного файла с нечетным числом строк, например

KEY 4048:1736 string
3
KEY 0:1772 string

paste не будет ссылаться на символ разделения на последней строке:

$ paste -s -d ',\n' infile
KEY 4048:1736 string,3
KEY 0:1772 string

Ответ 13

Другие решения, использующие vim (только для справки).

Решение 1:

Откройте файл в vim vim filename, затем выполните команду :% normal Jj

Эту команду очень легко понять:

  • %: для всех строк,
  • нормальный: выполнить нормальную команду
  • Jj: выполнить команду Join, а затем перейти к строке ниже

После этого сохраните файл и выйдите с помощью :wq

Решение 2:

Выполните команду в оболочке, vim -c ":% normal Jj" filename, затем сохраните файл и выйдите с помощью :wq.

Ответ 14

nawk '$0 ~ /string$/ {printf "%s ",$0; getline; printf "%s\n", $0}' filename

Это означает, что

$0 ~ /string$/  ## matches any lines that end with the word string
printf          ## so print the first line without newline
getline         ## get the next line
printf "%s\n"   ## print the whole line and carriage return

Ответ 15

В случае, когда мне нужно было объединить две строки (для облегчения обработки), но разрешить данные за конкретным, я нашел это полезным

data.txt

string1=x
string2=y
string3
string4
cat data.txt | nawk '$0 ~ /string1=/ { printf "%s ", $0; getline; printf "%s\n", $0; getline } { print }' > converted_data.txt

вывод тогда выглядит так:

converted_data.txt

string1=x string2=y
string3
string4

Ответ 16

Самый простой способ:

  • Удалите четные строки и запишите их в некоторый временный файл 1.
  • Удалить нечетные строки и записать их в некоторый временный файл 2.
  • Объедините два файла в одном, используя команду вставки с -d (означает удаление пространства)

sed '0~2d' file > 1 && sed '1~2d' file > 2 && paste -d " " 1 2

Ответ 17

perl -0pE 's{^KEY.*?\K\s+(\d+)$}{ $1}msg;' data.txt > data_merged-lines.txt

-0 копирует весь файл, а не читает его по очереди.
pE обертывает код циклом и выводит результат, см. подробности в http://perldoc.perl.org/perlrun.html;
^KEY сопоставить "KEY" в начале строки, после чего следует нежелательное соответствие чего-либо (.*?) перед последовательностью

  • одно или несколько пробелов \s+ любого типа, включая разрывы строк;
  • одна или несколько цифр (\d+), которые мы фиксируем, а затем снова вставляем как $1;

за которым следует конец строки $.

\K удобно исключает все из его левой части из подстановки, поэтому { $1} заменяет только 1-2 последовательности, см. http://perldoc.perl.org/perlre.html.

Ответ 18

Более общее решение (допускает объединение нескольких последующих строк) в виде оболочки script. Это добавляет линию между каждым, потому что мне нужна видимость, но это легко исправить. В этом примере заканчивается строка "ключ": и никаких других строк не было.

#!/bin/bash
#
# join "The rest of the story" when the first line of each   story
# matches $PATTERN
# Nice for looking for specific changes in bart output
#

PATTERN='*:';
LINEOUT=""
while read line; do
    case $line in
        $PATTERN)
                echo ""
                echo $LINEOUT
                LINEOUT="$line"
                        ;;
        "")
                LINEOUT=""
                echo ""
                ;;

        *)      LINEOUT="$LINEOUT $line"
                ;;
    esac        
done

Ответ 19

Попробуйте следующую строку:

while read line1; do read line2; echo "$line1 $line2"; done <old.txt>new_file

Вставить разделитель между

"$line1 $line2";

например. если разделитель |, то:

"$line1|$line2";

Ответ 20

Вы можете использовать xargs следующим образом:

xargs -a file