web-dev-qa-db-ja.com

コマンドラインから2行ごとに1つにマージする方法は?

次の形式のテキストファイルがあります。最初の行は「KEY」であり、2行目は「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

2行を1行にマージするにはどうすればよいですか?

122
shantanuo

awk:

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

出力の最後に空の行があることに注意してください。

sed:

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

pasteはこのジョブに適しています。

paste -d " "  - - < filename
205
glenn jackman

Sed、awk、grepの代替:

xargs -n2 -d'\n'

これは、N行を結合し、スペースで区切られた出力のみが必要な場合に最適です。

私の最初の答えはxargs -n2で、行ではなく単語で区切ります。 -dを使用して、任意の1文字で入力を分割できます。

29
nnog

絞首刑よりも犬を殺す方法がたくさんあります。 [1]

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

引用符の中に好きな区切り文字を入れてください。


参照:

  1. もともとは「猫の皮をむく方法はたくさんあります」が、ペットとは関係のない、より潜在的な起源の表現に戻りました。
25
ghoti

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

コメントの Ed Morton で示されているように、安全性のためにブレースを追加し、移植性のために括弧を追加する方が適切です。

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

ORSはOutput Record Separatorの略です。ここで行っているのは、行番号を格納するNRを使用して条件をテストすることです。 NRのモジュロが真の値(> 0)である場合、デフォルトでスペースであるFS(フィールドセパレーター)の値に出力フィールドセパレーターを設定します。それ以外の場合、改行であるRS(レコードセパレーター)の値を割り当てます。

,をセパレータとして追加する場合は、次を使用します。

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

Bashでの私のソリューションは次のとおりです。

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

以前のソリューションは機能すると思われますが、ドキュメント内で単一の異常が発生した場合、出力はバラバラになります。以下は少し安全です。

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

「ex」は、sed、awk、grepなどと同じファミリーにあるスクリプト可能な行エディターです。探しているものだと思います。多くの最新のviクローン/後続バージョンにもviモードがあります。

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

これは、「KEY」に一致する場合、各行に対して次の行のj oinを実行します。そのコマンドが(すべての行に対して)完了したら、w riteおよびq uitを発行します。

7
Justin

このようなawkを使用して、2組の行を組み合わせることができます。

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

Perlがオプションの場合、次を試すことができます。

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

glenn jackman's answer を使用したわずかなバリエーション:pasteの使用:-d delimiterオプションの値に複数の文字が含まれる場合、pasteは文字を1つずつ循環し、-sオプションと組み合わせて、同じ入力ファイルを処理します。

つまり、必要なものは何でも使用でき、セパレーターとエスケープシーケンス\nを使用して、一度に2行をマージできます。

コンマを使用:

$ 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

このcannotが行うことは、複数の文字で構成されるセパレータを使用することです。

おまけに、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
3
Benjamin W.

次のviコマンドも使用できます。

:%g/.*/j
3
Jdamian
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
1
Shahab Khan

Vimを使用した別のソリューション(参照用)。

ソリューション1

Vim vim filenameでファイルを開き、コマンド:% normal Jjを実行します

このコマンドは簡単に理解できます:

  • %:すべての行に対して、
  • normal:通常のコマンドを実行します
  • Jj:Joinコマンドを実行して、次の行にジャンプします

その後、ファイルを保存して:wqで終了します

ソリューション2

シェルでコマンドvim -c ":% normal Jj" filenameを実行し、ファイルを保存して:wqで終了します。

1
Jensen

(処理を簡単にするために)2行を結合する必要があるが、特定の部分を過ぎたデータを許可する必要がある場合、これが役立つことがわかりました。

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
1
Ben Taylor

最も簡単な方法は次のとおりです。

  1. 偶数行を削除して、一時ファイル1に書き込みます。
  2. 奇数行を削除して、一時ファイルに書き込みます2。
  3. Pasteコマンドに-dを使用して2つのファイルを1つに結合します(スペースの削除を意味します)
sed '0~2d' file > 1 && sed '1~2d' file > 2 && paste -d " " 1 2
0
Serg
Perl -0pE 's{^KEY.*?\K\s+(\d+)$}{ $1}msg;' data.txt > data_merged-lines.txt

-0は、ファイルを1行ずつ読み取るのではなく、ファイル全体を取得します。
pEはループでコードをラップして出力を出力します。詳細は http://perldoc.Perl.org/perlrun.html ;をご覧ください。
^KEYは、行の先頭で「KEY」に一致し、その後に続くシーケンスの前に、貪欲ではない任意の一致(.*?)が続きます

  1. 改行を含むあらゆる種類の1つ以上のスペース\s+
  2. キャプチャし、後で(\d+)として再挿入する1つ以上の数字$1;

その後に$行の終わりが続きます。

\Kは、その左側のすべてを置換から便利に除外するため、{ $1}は1-2シーケンスのみを置き換えます。 http://perldoc.Perl.org/perlre.html を参照してください。

0
Onlyjob

シェルスクリプトとしてのより一般的なソリューション(複数のフォローアップ行を結合できます)。可視性が必要だったので、これはそれぞれの間に線を追加しますが、それは簡単に修正できます。この例は、「キー」行が:で終わる場所で、他の行はありません。

#!/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
0
Jan Parcel