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


у меня есть текстовый файл со следующим форматом. Первая строка-это "ключ", а вторая строка - "значение".

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

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

20 105

20 ответов:

awk:

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

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

sed:

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

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

paste -d " "  - - < filename

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

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

поставить любой разделитель, который вам нравится внутри кавычек.


ссылки:

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

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

xargs -n2 -d'\n'

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

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

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

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

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

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

вот еще один способ с 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 (разделитель записей), который является новой строкой.

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

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

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

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

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

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

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

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

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

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

:%g/.*/j

небольшая вариация на ответ Гленна Джекмана используя paste: если значение -d опция разделителя содержит более одного символа,paste циклы через символы один за другим, и в сочетании с -s options продолжает делать это при обработке одного и того же входного файла.

это означает, что мы можем использовать все, что мы хотим иметь в качестве разделителя плюс 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
KEY 0:1772 string
KEY 4192:1349 string
KEY 7329:2407 string
KEY 0:1774 string

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

в качестве бонуса, если 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
nawk ' ~ /string$/ {printf "%s ",; getline; printf "%s\n", }' filename

это читается как

 ~ /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

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

данные.txt

string1=x
string2=y
string3
string4

данные кошку.тхт | nawk '$0 ~ /строка1=/ { функции printf "%ы ", $0; Гэтлину; функции printf "%З\П", $0; Гэтлину } { печать }' > converted_data.txt

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

converted_data.txt

string1=x string2=y
string3
string4

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

Решение 1:

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

эта команда quit легко понять:

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

после этого, сохраните файл и выйдите с :wq

решение 2:

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

самый простой способ-это здесь:

  1. удалите четные строки и запишите их в некоторый временный файл 1.
  2. удалите нечетные строки и запишите их в некоторый временный файл 2.
  3. объединить два файла в один с помощью команды вставить С-D (означает удалить пробел)

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

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

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

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

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

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

#!/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

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

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

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

"$line1 $line2";

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

"$line1|$line2";

можно использовать xargs такой:

xargs -a file