두 줄을 모두 명령 줄에서 하나로 병합하는 방법은 무엇입니까?


151

다음 형식의 텍스트 파일이 있습니다. 첫 번째 줄은 "KEY"이고 두 번째 줄은 "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

두 줄을 하나로 병합하려면 어떻게합니까?


이 작업에는 많은 방법이 있습니다! 나는 짓을했는지 와 작은 벤치 pr, paste, awk, xargs, sedpure bash ! ( Bashxargs 보다 느리고 느리다 !)
F. Hauri

답변:


182

awk :

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

출력 끝에 빈 줄이 있습니다.

sed :

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

컬러 출력에서는 작동하지 않습니다. 나는이 Q & A에서 모든 것을 시도했지만 출력이 ansi 색상 일 때 아무것도 작동하지 않았습니다. 우분투 13.04에서 테스트
레오 Gallucci

1
@ elgalu : ANSI 색상은 이스케이프 문자 조합 일뿐입니다. 당신이 가진 것을보기 위해 그러한 출력에서 ​​16 진수 편집을하십시오.
not2qubit

7
printf확장 솔루션은 과 같은 확장 문자열 %s이 안에 있으면 깨질 수 있습니다 $0. 이러한 실패는 다음과 같이 피할 수 있습니다.'NR%2{printf "%s ",$0;next;}1'
ghoti

9
Google이 실제로 어렵 기 때문에 1닫는 중괄호는 무엇을 의미합니까?
erikbwork

5
@ erikb85 여기로 가십시오 stackoverflow.com/questions/24643240/…
Viraj

243

paste 이 직업에 좋습니다 :

paste -d " "  - - < filename

10
나는 이것이 sed 나 awk를 사용하지 않더라도 가장 좋은 해결책이라고 생각합니다. 홀수의 입력 인 Kent의 awk 솔루션은 마지막 줄 바꿈을 건너 뛰고 sed 솔루션은 entirty의 마지막 줄을 건너 뛰고 내 솔루션은 마지막 줄을 반복합니다. paste반면에, 완벽하게 행동합니다. +1.
ghoti

8
나는 종종 사용 cut하지만 항상 잊어 버립니다 paste. 이 문제를 해결합니다. stdin의 모든 줄 을 결합 해야 하고 쉽게 수행했습니다 paste -sd ' ' -.
클린트 Pachl

4
간단하고 아름다운!
krlmlr

8
그래서 -평균 표준 입력, 그래서 paste - -당신은 내가 기대 원하는 표준 입력에서 평균 읽기, 다음 표준 입력에서 읽고, 당신은 그들 중 많은으로 적재 할 수 있습니다.
ThorSummoner

1
예, @ThorSummoner ... 세 줄을 모두 한 줄에 붙여 넣고 붙여 넣기를 수행해야 완벽하게 작동했습니다.
Daniel Goldfarb

35

sed, awk, grep의 대안 :

xargs -n2 -d'\n'

이것은 N 행을 결합하고 공백으로 구분 된 출력 만 필요한 경우에 가장 좋습니다.

내 원래의 대답은 xargs -n2줄이 아닌 단어로 구분됩니다. -d입력을 단일 문자로 나누는 데 사용할 수 있습니다.


4
이것은 좋은 방법이지만 줄이 아닌 단어에서 작동합니다. 라인에서 작동하게하려면 다음을 추가 할 수 있습니다.-d '\n'
Don Hatch

2
와, 나는 일반 xargs사용자이지만 이것을 몰랐습니다. 좋은 팁.
Sridhar Sarnobat가

1
나는 이것을 좋아한다. 깨끗 해요
Alexander Guo

28

교수형보다 개를 죽이는 방법이 더 많습니다. [1]

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

따옴표 안에 원하는 구분 기호를 넣으십시오.


참고 문헌 :

  1. 원래 "고양이를 껍질을 벗기는 많은 방법"은 애완 동물과는 아무런 관련이없는 더 오래되고 잠재적으로 시작되는 표현으로 되돌아갔습니다.

나는이 솔루션을 좋아한다.
luis.espinal

5
고양이 주인으로서 나는 이런 종류의 유머를 좋아하지 않습니다.
witkacy26

4
@ witkacy26, 우려 사항에 따라 조정 된 표현.
ghoti

나는이 awk 솔루션을 사랑하지만 어떻게 작동하는지 이해하지 못합니다 : S
Rubendob

@ Rubendob-awk는 입력의 각 줄을 읽어서 변수에 넣습니다 $0. 이 getline명령은 또한 "다음"입력 행을 잡고에 배치합니다 $0. 따라서 첫 번째 문은 첫 번째 줄을 가져오고 print 명령은 변수에 저장된 내용을 key쉼표가 포함 된 문자열과 함께 사용하여 가져온 줄과 연결합니다 getline. 더 깨끗해? :)
ghoti

12

bash의 해결책은 다음과 같습니다.

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

11

이전 솔루션이 작동하는 것처럼 보이지만 문서에서 단일 이상이 발생하면 결과물이 조각화됩니다. 아래는 조금 더 안전합니다.

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

3
왜 더 안전한가요? 무엇을 /KEY/합니까? 무엇을 않는 p말합니까?
스튜어트

/KEY/줄을 검색합니다 KEY. p인쇄는 밖으로 발생합니다. 그것은 KEY안에있는 라인에만 작업을 적용하기 때문에 더 안전 합니다.
minghua

11

다른 방법은 다음과 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출력 레코드 구분 기호를 나타냅니다. 여기서 우리는 NR행 번호를 저장 하는 조건을 사용하여 조건을 테스트합니다 . 모듈러스 NR가 참 값 (> 0)이면 출력 필드 구분 기호를 FS기본적으로 공백 인 (필드 구분 기호) 값 으로 설정합니다. 그렇지 않으면 값을RS (레코드 구분 기호) 줄 바꿈으로 지정합니다.

,구분 기호 로 추가 하려면 다음을 사용하십시오.

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

1
확실히 올바른 접근 방식이므로 +1이지만 레코드 인쇄의 기본 동작을 호출하기 위해 평가되는 조건이 무엇인지 궁금합니다. 과제가 성공 했습니까? ORS가 0 또는 null 문자열이 아닌 값을 가져 와서 숫자 비교 대신 찌르기를 올바르게 추측 하기 때문에 간단하게 ORS처리 true됩니까? 다른 것입니까? 확실하지 않아서로 작성했습니다 awk '{ORS=(NR%2?FS:RS)}1' file. 이식성을 보장하기 위해 삼항식을 괄호로 묶었습니다.
Ed Morton

1
@EdMorton 네, 방금이 답변에 대한 몇 가지 공감대가 안전을 위해 중괄호를 포함하도록 업데이트하는 것을 보았습니다. Parens도 추가합니다.
jaypal 싱

7

"ex"는 sed, awk, grep 등과 같은 제품군에있는 스크립트 가능한 라인 편집기입니다. 여러분이 찾고있는 것일 수도 있습니다. 많은 최신 vi 복제 / 성공 업체에도 vi 모드가 있습니다.

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

이것은 일치하는 경우 "KEY"는 수행, 각 행에 대해 말한다 J를 다음 줄의 OIN. (모든 라인에 대한) 그 명령이 완료 후, 발급 의식 및 Q UIT.


4

Perl이 옵션이면 다음을 시도해보십시오.

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

-0펄에게 레코드 구분 기호를 설정하도록 설정 $/)하는가? ( null 로 설정하여 일치하는 패턴으로 여러 줄에 걸쳐있을 수 있습니다. 맨 페이지는 실제로 의미가 무엇인지 알아 내기에는 너무 기술적 인 내용입니다.
Sridhar Sarnobat

4

다음과 같이 awk를 사용하여 두 쌍의 줄을 결합 할 수 있습니다.

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

4

vim을 사용하는 다른 솔루션 (참조 용).

해결책 1 :

vim vim filename에서 파일을 연 다음 명령을 실행하십시오.:% normal Jj

이 명령은 이해하기 매우 쉽습니다.

  • % : 모든 줄에 대해
  • normal : 일반 명령을 실행합니다
  • Jj : Join 명령을 실행 한 후 아래 줄로 이동

그런 다음 파일을 저장하고 :wq

해결책 2 :

쉘에서 명령을 실행 한 vim -c ":% normal Jj" filename다음 파일을 저장하고로 종료하십시오 :wq.


또한 리 맵핑 된 경우 norm!보다 강력합니다 . vim 솔루션의 경우 +1 normalJ
qeatzy

@qeatzy 저를 가르쳐 주셔서 감사합니다. 알고 매우 기뻐요. ^ _ ^
Jensen

3

다음 vi 명령을 사용할 수도 있습니다.

:%g/.*/j

또는 :%g//j필요한 것은 조인 을 실행하기 위한 일치 이고 null 문자열은 여전히 ​​유효한 정규식입니다.
ghoti

1
@ghoti, Vim에서는 just을 사용할 때 //이전 검색 패턴이 대신 사용됩니다. 이전 패턴이없는 경우 Vim은 단순히 오류를보고하고 아무것도하지 않습니다. Jdamian의 솔루션은 항상 작동합니다.
Tzunghsing David Wong

1
@TzunghsingDavidWong-그것은 vim 사용자에게 좋은 포인터입니다. 나를 위해, 질문이나 대답이 vim을 언급하지 않았습니다.
ghoti

3

에 약간의 변화 글렌 잭맨의 대답 사용은 paste다음의 값 경우 -d구분 옵션은 하나 이상의 문자가 포함되는 경우, paste문자 하나 하나와 결합을 통해 사이클 -s옵션은 동일한 입력 파일을 처리하는 동안 것을하고 유지합니다.

\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

1
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

더 쉬운 처리를 위해 두 줄을 결합해야하지만 특정 데이터를 지나서 데이터를 허용하는 경우 이것이 유용하다는 것을 알았습니다.

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

출력은 다음과 같습니다.

conversion_data.txt

string1=x string2=y
string3
string4

1

vim을 사용하는 또 다른 방법은 다음과 같습니다.

:g/KEY/join

이것은 join단어가있는 모든 줄에 (아래 줄에) 적용됩니다 KEY. 결과:

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

0

가장 간단한 방법은 다음과 같습니다.

  1. 짝수 줄을 제거하고 임시 파일 1에 씁니다.
  2. 홀수 줄을 제거하고 임시 파일 2에 씁니다.
  3. paste 명령을 -d와 함께 사용하여 두 파일을 하나로 결합합니다 (삭제 공간을 의미 함).

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

0
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"를 찾은 다음 .*?순서의 앞에 욕심없는 일치 ( )

  1. \s+줄 바꿈을 포함하여 모든 종류의 하나 이상의 공백 ;
  2. 하나 이상의 숫자 (\d+)를 캡처하고 나중에 다시 삽입합니다 $1.

줄 끝이 이어집니다 $.

\K왼쪽의 모든 항목을 { $1}대체 에서 편리하게 제외하므로 1-2 시퀀스 만 대체합니다 ( http://perldoc.perl.org/perlre.html 참조) .


0

보다 일반적인 솔루션 (2 개 이상의 후속 라인을 결합 할 수 있음)을 쉘 스크립트로 사용합니다. 이것은 가시성이 필요했기 때문에 각각 사이에 선을 추가하지만 쉽게 해결할 수 있습니다. 이 예제는 "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

-1

다음 줄을 시도하십시오.

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

사이에 구분 기호를 넣습니다

"$line1 $line2";

예를 들어 구분자가 |인 경우 :

"$line1|$line2";

이 답변에는 4 년 전에 게시 된 Hai Vu의 답변에 제공되지 않은 내용이 추가되지 않았습니다 .
fedorqui 'SO 중지 피해'

부분적으로 동의하며 설명을 추가하려고 시도하고 더 일반적인 것은 오래된 파일도 편집하지 않습니다. 제안 해 주셔서 감사합니다
Suman

-2

다음 xargs과 같이 사용할 수 있습니다 :

xargs -a file

% cat> 파일 abc % xargs -a 파일 abc % 작동합니다
RSG

그것은 않습니다 뭔가, 그래,하지만 영업 이익을 위해 무엇을 요구합니다. 특히, 가능한 많은 행을 연결합니다. 실제로 원하는 것을 얻을 수는 xargs -n 2있지만이 답변은 이것을 전혀 설명하지 않습니다.
tripleee
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.