구분자를 사용하여 목록을 한 줄로 바꾸기


17

이 형식으로 IP 주소 목록을 가져와야합니다.

 134.27.128.0
 111.245.48.0
 109.21.244.0

파이프를 사이에두고이 형식으로 바꾸십시오 (IP 구성).

134.27.128.0 | 111.245.48.0 | 109.21.244.0 | 103.22.200.0/22

나는 그것이 찾기 및 바꾸기 명령이라고 생각 sed하지만 작동시킬 수는 없습니다.


3
tr개행을 |파이프 에 붙이고 싶 습니까? 처럼 <ipfile tr \\n \| >outfile?
mikeserv

주변 공간이 |필요합니까?
cuonglm

2
@uselesslinuxman-아니요. 입력 리디렉션이 필요합니다 <. 그래서 <mydoc tr \\n \| >mydoc2. 그러나 그것은 당신에게 공간을 얻지 못할 것입니다. 아마도 가장 빠른 해결책은 다음과 같습니다.paste -d' | ' mydoc /dev/null /dev/null >mydoc2
mikeserv

1
@ mikeserv : 나는 그것이 작동하지 않을 것이라고 생각합니다. paste각 파일에서 해당 줄을 씁니다. 이 없으면 -s파일에있는 줄 수를 다시 얻게됩니다.
cuonglm

2
@ val0x00ff : 나는 읽고 당신을 초대 unix.stackexchange.com/q/169716/38906
cuonglm

답변:


16

Famous Sed One-Liners Explained, Part I : : 39를 기반으로 sed를 사용 합니다. 백 슬래시 "\"로 끝나는 경우 다음 행을 추가합니다 (여기서는 백 슬래시 관련 부분을 무시하고 줄 \n바꿈을 필요한 |구분 기호) :

sed -e :a -e '$!N; s/\n/ | /; ta' mydoc > mydoc2

생산해야한다 mydoc2

134.27.128.0 |  111.245.48.0 |  109.21.244.0

@don_crissti 죄송합니다. 죄송합니다. 형식-수정되었습니다, 감사합니다
steeldriver

불행히도 실제로는 실제로 작동하지 않습니다. 최소한 무제한 스트림이 아닙니다. 이 작업을 수행하면 입력 전체를 한 번에 한 줄씩 삼켜야하며 모두 소화 할 때까지 출력에 단일 바이트조차 쓸 수 없습니다. 모두 한 줄로 변환됩니다. 다루기 어려우며 segfault가 발생하기 쉽습니다.
mikeserv

백만 개의 IP는 <16M입니다. 여기서 한계를 날리려면 엄청나게 큰 목록이 필요합니다. 입력 파일 크기에 대해 O (N ^ 2)를 실행하므로 eof 검색을 사용하는 것이 더 문제가됩니다. sed 'H;1h;$!d;x;s/\n/ | /g'선형입니다.
jthill

@jthill-POSIX sed는 8K 의 패턴 공간 만 보장합니다 . 그것은 16M보다 훨씬 적습니다.
mikeserv

9

나는 이들 (+ 일부 대안) 중 일부가 다소 큰 파일 ( 163MiBIP줄에 하나씩 ~ 1,300 만 줄)로 속도면에서 어떻게 작동하는지 궁금했습니다 .

wc -l < iplist
13144256

결과 ( sync; echo 3 > /proc/sys/vm/drop_caches각 명령 후; 몇 시간 후에 역순으로 테스트를 반복했지만 차이점은 무시할 수있었습니다 gnu sed.

스틸 드라이버 :
매우 느립니다. 2 분 동안 기다린 후에 중단되었으므로 결과가 없습니다.

cuonglm :

awk 'FNR!=1{print l}{l=$0};END{ORS="";print l}' ORS=' | ' iplist

real    0m3.672s

perl -pe 's/\n/ | / unless eof' iplist

real    0m12.444s

mikeserv :

paste -d\  /dev/null iplist /dev/null | paste -sd\| - 

real    0m0.983s

jthill :

sed 'H;1h;$!d;x;s/\n/ | /g' iplist

real    0m4.903s

아비 나쉬 라지 :

time python2.7 -c'
import sys
with open(sys.argv[1]) as f:
    print " | ".join(line.strip() for line in f)' iplist

real    0m3.434s

val0x00ff :

while read -r ip; do printf '%s | ' "$ip"; done < iplist

real    3m4.321s

의미 184.321s합니다. 당연히, 이것은 mikeserv 솔루션 보다 200 배 느립니다 .



awk를 사용 하는 다른 방법은 다음과 같습니다 .

awk '$1=$1' RS= OFS=' | ' iplist

real    0m4.543s

awk '{printf "%s%s",sep,$0,sep=" | "} END {print ""}' iplist

real    0m5.511s

펄 :

perl -ple '$\=eof()?"\n":" | "' iplist

real    0m9.646s

xargs :

xargs <iplist printf ' | %s' | cut -c4-

real    0m6.326s

head + paste + tr + cat 조합 :

{ head -n -1 | paste -d' |' - /dev/null /dev/null | tr \\n \ ; cat ; } <iplist

real    0m0.991s

보유 GNU coreutils하고 있고 IP 목록이 실제로 크지 않은 경우 (최대 50000 개의 IP) 다음과 pr같이 할 수도 있습니다 .

pr -$(wc -l infile) -tJS' | ' -W1000000 infile >outfile

어디

-$(wc -l infile)         # no. of columns (= with no. of lines in your file)
-t                       # omit page headers and trailers
-J                       # merge lines
-S' | '                  # separate columns by STRING
-W1000000                # set page width

예를 들어 6 줄 파일의 경우 :

134.28.128.0
111.245.28.0
109.245.24.0
128.27.88.0
122.245.48.0
103.44.204.0

명령 :

pr -$(wc -l <infile) -tJS' | ' -W1000 infile

출력 :

134.28.128.0 | 111.245.28.0 | 109.245.24.0 | 128.27.88.0 | 122.245.48.0 | 103.44.204.0

don- while ... read루프에 대해 @ val0x00ff의 질문에 제안을 추가 할 수 있습니까? 벤치 마크에서 163k read()write()호출이 무엇을 번역 하는지 궁금합니다 . 그건 그렇고 큰 대답입니다.
mikeserv

1
@ mikeserv-문제 없습니다, 내가 할 것입니다 ( 실제로 느릴 것입니다 ).
don_crissti

정말 멋진 링크입니다. 나는 특히 저자가 비슷한 6 년 된 벤치 마크에 대한 링크를 제공한다는 것을 좋아합니다. 당신이 그 통지 수행 sed의 해당 시간에 서 개선 된 것으로 보인다 (및 정규 표현식 엔진에 아마 단지 아주 약간의 변화가 있었다) 하지만이 grep극적으로 성능에 뒤 떨어진 것 같다 (특히 긴 행에 대한) ? perl엔진에 추가 한 결과가 그 결과와 관련이 있는지 궁금합니다 ... 심연dash 이 아닌 것도 깔끔합니다 . 여기 가능성이 훨씬 느린 w 것 / 일반은 앞에 추가. bashIFS=
mikeserv

흠 ... 그 링크는 또 다른 강력한 지표이며, 실제로 버클을 잡고 C를 배워야 마침내 사용할 lex수 있습니다.
mikeserv

8

awk 를 사용할 수 있습니다 :

awk 'FNR!=1{print l}{l=$0};END{ORS="";print l}' ORS=' | ' file > new_file

ORS=' | '출력 레코드 구분 기호' | '개행 문자 대신 설정하십시오 .

또는 다음 위치에서 편집하십시오 perl.

perl -pe 's/\n/ | / unless eof' file

고마워요 방금 paste작동 방식을 배웠습니다 . 매우 감사.
mikeserv

@ mikeserv : 천만에요. don_crissti가 벤치 마크에 표시된 것처럼 paste솔루션이 가장 빠릅니다.
cuonglm

출력은 개행으로 끝나지 않습니다. 블록 ORS=""내부 를 교체해야 할 수도 있습니다 . ENDORS="\n"
phk

4

그래서 나는 모든 것이 잘못되었다. 그리고이 질문은 나에게 많은 것을 가르쳐 주었다 paste. cuonglm이 올바르게 지적했듯이, in inial paste파일이 없으면 infile 목록 -s의 마지막 \newline이 출력에 추가 될 때 항상 출력됩니다. 나는 paste -s행동이 기본 모드 라는 믿음으로 착각했습니다. 이것은 분명히 busybox paste기뻐 하는 오해입니다 . 다음 명령은 광고 된대로 작동합니다 busybox.

paste -d'|  ' - - infile </dev/null >outfile

그러나 사양에 따라 작동하지 않습니다. 올바르게 구현 paste되면 \n각 시퀀스에 대해 후행 줄 바꿈이 추가 됩니다. 여전히, 그것은 결국 큰 문제가 아닙니다.

paste -d\  - infile - </dev/null | paste -sd\| - >outfile

@don_crissti-단깃. 바보 태블릿. 분명히해야 할 일은 두 개의 페이스트입니다.
mikeserv

1
글쎄, pr명심했지만 분명히 큰 입력 파일로 증기가 부족하여 실제로 속도를 테스트 할 수는 없었지만 합리적인 길이의 파일을 사용하면 정상적으로 작동합니다. 당신은 해결책이 훨씬 빠릅니다 (놀랍지 않습니다- paste정말 빠릅니다).
don_crissti

4

tr과 sed를 가진 1 개의 강선 :

cat file | tr '\n' '|' | sed 's/||$/\n/'
134.27.128.0|111.245.48.0|109.21.244.0

후행 파이프 2 개를 삭제하는 이유는 무엇입니까? 입력이 빈 줄 (두 줄 바꿈)로 끝나는 경우 끝에 2 만 있습니다.
JigglyNaga

3

활용 vim:

vim -n -u NONE -c '1,$-1s/\n/ | /g|wq!' data

설명:

-n 스왑 파일 비활성화

-u NONE 모든 초기화를 건너 뛰는 데 사용됩니다.

-c {command} 파일을 읽은 후 명령을 실행하십시오.

1,$-1s/\n/ | /g되는 s/\n/ | /g범위의 (공간 배관 공간 개행 교환) 1,$-1s(마지막 라인에 1 라인 - 1)

wq! 강제 쓰기 및 종료


노트 :

파일의 실제 크기에 따라 나쁜 생각 일 수 있습니다.


1
기본적으로 이러한 명령 중 거의 모든 하나가 달성해야 할 작업을 수행하기 때문에 모두에게 감사합니다. 나는 다시 언제 갇 히면 지금 어디로 올지 알고 있습니다. 감사합니다
uselesslinuxman

2

파이썬을 통해.

$ python -c '
import sys
with open(sys.argv[1]) as f:
    print " | ".join(line.strip() for line in f)' file

전에 공백 print이 매우 중요했습니다.


2

여기에 다른 하나가 사용됩니다. xxd

xxd -c1 -ps data | sed '$!s/0a/207c20/' | xxd -r -ps

2

완전성을 위해 여기에 다른 awk기반 솔루션이 있습니다.이 솔루션은 전혀 사용하지 않습니다 ORS.

awk 'BEGIN { ORS="" } { print p$0; p=" | " } END { print "\n" }' file > new_file

설명은 /unix//a/338121/117599의 내 게시물을 참조하십시오 .

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.