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

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

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 ответов


на 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:

выполните команду в shell,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.


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

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