백 슬래시 문자로 끝나는 모든 줄을 어떻게 결합 할 수 있습니까?


35

sed 또는 awk와 같은 일반적인 명령 줄 도구를 사용하면 백 슬래시와 같이 주어진 문자로 끝나는 모든 줄을 연결할 수 있습니까?

예를 들어 파일이 다음과 같습니다.

foo bar \
bash \
baz
dude \
happy

이 출력을 얻고 싶습니다 :

foo bar bash baz
dude happy

1
파일을 통해 전달 cpp:)
imz-Ivan Zakharyaschev

정말 멋진 답변이 많이 있습니다. 모두 답변으로 표시 할 수 있기를 바랍니다. awk, sed 및 perl에 대한 훌륭한 감사의 말을 들었습니다. 이것들은 훌륭한 예입니다.
코리 클라인

답변:


26

더 짧고 간단한 sed 솔루션 :

sed  '
: again
/\\$/ {
    N
    s/\\\n//
    t again
}
' textfile

또는 GNU를 사용하는 경우 하나의 라이너 sed:

sed ':x; /\\$/ { N; s/\\\n//; tx }' textfile

1
좋은 것 ... 나는 이것을 처음으로 보았고 그것을 이해할 수 없었습니다 (그래서 너무 힘든 바구니에 들어 가지 않을 것입니다) ... 그러나 Gilles의 대답을 심도있게 살펴본 후에 (시간이 꽤 걸렸습니다) 나는 당신의 대답을 다시 보았고 이해할 수 있다고 생각했습니다. 나는 이해하기 시작했다고 생각합니다 sed. :) ... 당신은 패턴 공간에 직접 각 줄을 추가하고 있으며, "정상적으로 끝나는"줄이 나타나면 전체 패턴 공간이 떨어지고 자동 인쇄됩니다 (-n 옵션이 없기 때문에). .. +1
Peter.O

@fred : 고맙게도 sed도 이해하기 시작한 것 같아요. 여러 줄 편집을위한 훌륭한 도구를 제공하지만 필요한 내용이 간단하지 않거나 가독성이 높은 것을 얻기 위해 그것들을 혼합하는 방법 ...
neurino

DOS 줄 끝을 조심하십시오. 캐리지 리턴 또는 \ r!
user77376

1
무엇이 잘못 sed -e :a -e '/\\$/N; s/\\\n//; ta'
Isaac Isaac

18

perl을 사용하는 것이 가장 쉬울 것입니다.

perl -p -e 's/\\\n//'

짧고 간단한, 나는 그 하나를 좋아한다 +1 그리고 그는 sed 또는 awk를 명시 적으로 요구하지 않았다
rudolfson


2

이것은 대답이 아닙니다. 에 대한 부수적 인 문제 sed입니다.

구체적으로, 나는 Gilles의 sed명령 을 하나씩 분해하여 이해해야했습니다 ... 나는 그것에 대해 약간의 노트를 작성하기 시작했고, 여기 누군가에게 유용 할 것이라고 생각했습니다 ...

그래서 여기있다 ... 질 '나오지도 스크립트기록 형식 :


#!/bin/bash
#######################################
sed_dat="$HOME/ztest.dat"
while IFS= read -r line ;do echo "$line" ;done <<'END_DAT' >"$sed_dat"
foo bar \
bash \
baz
dude \
happy
yabba dabba 
doo
END_DAT

#######################################
sedexec="$HOME/ztest.sed"
while IFS= read -r line ;do echo "$line" ;done <<'END-SED' >"$sedexec"; \
sed  -nf "$sedexec" "$sed_dat"

  s/\\$//        # If a line has trailing '\', remove the '\'
                 #    
  t'Hold-append' # branch: Branch conditionally to the label 'Hold-append'
                 #         The condition is that a replacement was made.
                 #         The current pattern-space had a trailing '\' which  
                 #         was replaced, so branch to 'Hold-apend' and append 
                 #         the now-truncated line to the hold-space
                 #
                 # This branching occurs for each (successive) such line. 
                 #
                 # PS. The 't' command may be so named because it means 'on true' 
                 #     (I'm not sure about this, but the shoe fits)  
                 #
                 # Note: Appending to the hold-space introduces a leading '\n'   
                 #       delimiter for each appended line
                 #  
                 #   eg. compare the hex dump of the follow 4 example commands:  
                 #       'x' swaps the hold and patten spaces
                 #
                 #       echo -n "a" |sed -ne         'p' |xxd -p  ## 61 
                 #       echo -n "a" |sed -ne     'H;x;p' |xxd -p  ## 0a61
                 #       echo -n "a" |sed -ne   'H;H;x;p' |xxd -p  ## 0a610a61
                 #       echo -n "a" |sed -ne 'H;H;H;x;p' |xxd -p  ## 0a610a610a61

   # No replacement was made above, so the current pattern-space
   #   (input line) has a "normal" ending.

   x             # Swap the pattern-space (the just-read "normal" line)
                 #   with the hold-space. The hold-space holds the accumulation
                 #   of appended  "stripped-of-backslah" lines

   G             # The pattern-space now holds zero to many "stripped-of-backslah" lines
                 #   each of which has a preceding '\n'
                 # The 'G' command Gets the Hold-space and appends it to 
                 #   the pattern-space. This append action introduces another
                 #   '\n' delimiter to the pattern space. 

   s/\n//g       # Remove all '\n' newlines from the pattern-space

   p             # Print the pattern-space

   s/.*//        # Now we need to remove all data from the pattern-space
                 # This is done as a means to remove data from the hold-space 
                 #  (there is no way to directly remove data from the hold-space)

   x             # Swap the no-data pattern space with the hold-space
                 # This leaves the hold-space re-initialized to empty...
                 # The current pattern-space will be overwritten by the next line-read

   b             # Everything is ready for the next line-read. It is time to make 
                 # an unconditional branch  the to end of process for this line
                 #  ie. skip any remaining logic, read the next line and start the process again.

  :'Hold-append' # The ':' (colon) indicates a label.. 
                 # A label is the target of the 2 branch commands, 'b' and 't'
                 # A label can be a single letter (it is often 'a')
                 # Note;  'b' can be used without a label as seen in the previous command 

    H            # Append the pattern to the hold buffer
                 # The pattern is prefixed with a '\n' before it is appended

END-SED
#######

1
Neurino의 솔루션은 실제로 매우 간단합니다. 약간 복잡한 sed에 관해 말하면, 이것은 당신에게 관심이있을 수 있습니다 .
질 'SO-정지 존재 악마'

2

또 다른 일반적인 명령 줄 도구는 ed기본적으로 파일을 제자리에서 수정하므로 파일 권한을 수정하지 않은 상태로 둡니다 (자세한 내용 은 스크립트에서 ed 텍스트 편집기로 파일 편집ed 참조 ).

str='
foo bar \
bash 1 \
bash 2 \
bash 3 \
bash 4 \
baz
dude \
happy
xxx
vvv 1 \
vvv 2 \
CCC
'

# We are using (1,$)g/re/command-list and (.,.+1)j to join lines ending with a '\'
# ?? repeats the last regex search.
# replace ',p' with 'wq' to edit files in-place
# (using Bash and FreeBSD ed on Mac OS X)
cat <<-'EOF' | ed -s <(printf '%s' "$str")
H
,g/\\$/s///\
.,.+1j\
??s///\
.,.+1j
,p
EOF

2

read쉘없이 백 슬래시를 해석 한다는 사실을 사용하면 -r:

$ while IFS= read line; do printf '%s\n' "$line"; done <file
foo bar bash baz
dude happy

이는 데이터의 다른 백 슬래시 도 해석합니다 .


아니. 모든 백 슬래시를 제거하지는 않습니다 . 시도해보세요a\\b\\\\\\\\\\\c
Isaac

@Isaac Ah, 아마도 "다른 백 슬래시 해석"이라고 말했 을까요?
Kusalananda

1

전체 파일을 메모리에로드하는 간단한 솔루션입니다.

sed -z 's/\\\n//g' file                   # GNU sed 4.2.2+.

또는 이해 (출력) 줄 (GNU 구문)을 작동하는 여전히 짧은 것 :

sed ':x;/\\$/{N;bx};s/\\\n//g' file

한 줄에 (POSIX 구문) :

sed -e :x -e '/\\$/{N;bx' -e '}' -e 's/\\\n//g' file

또는 awk를 사용하십시오 (파일이 너무 커서 메모리에 맞지 않는 경우).

awk '{a=sub(/\\$/,"");printf("%s%s",$0,a?"":RS)}' file

0

@Giles 솔루션을 기반으로 한 Mac 버전은 다음과 같습니다.

sed ':x
/\\$/{N; s|\\'$'\\n||; tx
}' textfile

주요 차이점은 줄 바꿈이 표현되는 방식이며 더 이상 한 줄로 결합하면 줄 바꿈됩니다.


-1

cpp를 사용할 수는 있지만 출력을 병합 한 빈 줄과 sed로 제거 한 소개를 생성합니다. 아마 cpp-flags 및 옵션으로도 수행 할 수 있습니다.

echo 'foo bar \
bash \
baz
dude \
happy' | cpp | sed 's/# 1 .*//;/^$/d'
foo bar bash baz
dude happy

당신은 확실 cpp 하다 해결책은? 귀하의 예 echo에서 큰 따옴표로 묶인 with 문자열은 이미 곧은 텍스트를 출력하므로 cpp무의미합니다. (이것은 sed코드 에도 적용됩니다 .) 작은 따옴표 안에 문자열을 넣으면 cpp백 슬래시 만 제거하고 줄을 연결하지는 마십시오. ( cpp백 슬래시 앞에 공백이 없으면 분리 기호없이 분리 된 단어가 결합되면 연결 이 작동합니다.)
manatwork

@manatwork : Outsch! :) 나는 sed 명령이 작동했다는 것에 놀랐지 만, 물론 sed 명령은 아니지만 bash 자체는 백 슬래시-줄 바꿈을 이전 행의 연속으로 해석합니다.
사용자가 알 수 없음

그런 식으로 사용하면 cpp여전히 선을 연결하지 않습니다. 그리고 사용 sed은 확실히 불필요합니다. 사용 cpp -P:“ -P전 처리기의 출력에서 ​​라인
마커

당신의 명령이 나를 위해 작동하지 않습니다 : cpp: “-P: No such file or directory cpp: warning: '-x c' after last input file has no effect cpp: unrecognized option '-P:' cpp: no input filesA cpp --version공개 cpp (Ubuntu 4.4.3-4ubuntu5.1) 4.4.3-무엇? 우분투는 cpp를 패치하고 있습니까? 왜? 나는 GNU ... 읽을 것으로 예상 것
사용자 알 수없는

흥미 롭군 우분투는 cpp실제로 줄을 연결하고 공백을 남겨 둡니다. 더 흥미로운 것은 동일한 버전 4.4.3-4ubuntu5.1이 여기에있는 것 -P입니다. 그러나 그것은 라인 마커를 제거하고 빈 줄은 남아 있습니다.
manatwork
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.