Làm thế nào bạn có thể kết hợp tất cả các dòng kết thúc bằng một ký tự dấu gạch chéo ngược?


36

Sử dụng một công cụ dòng lệnh phổ biến như sed hoặc awk, có thể tham gia tất cả các dòng kết thúc bằng một ký tự đã cho, như dấu gạch chéo ngược không?

Ví dụ: đưa ra tệp:

foo bar \
bash \
baz
dude \
happy

Tôi muốn có được đầu ra này:

foo bar bash baz
dude happy

1
Chuyển tập tin qua cpp:)
imz - Ivan Zakharyaschev

Rất nhiều câu trả lời tuyệt vời, tôi ước tôi có thể đánh dấu tất cả chúng là câu trả lời! Cảm ơn vì cái nhìn tuyệt vời về awk, sed và perl, đây là những ví dụ tuyệt vời.
Cory Klein

Câu trả lời:


27

một giải pháp sed ngắn hơn và đơn giản hơn:

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

hoặc một lớp lót nếu sử dụng GNU sed:

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

1
tốt ... tôi ban đầu nhìn vào điều này và không thể hiểu nó (vì vậy nó không nằm trong giỏ quá cứng) ... nhưng sau khi nhìn sâu vào câu trả lời của Gilles (mất khá nhiều thời gian) Tôi đã có một cái nhìn khác về câu trả lời của bạn và nó có vẻ dễ hiểu Tôi nghĩ rằng tôi đang bắt đầu hiểu sed:) ... Bạn đang nối trực tiếp từng dòng vào không gian mẫu và khi một dòng "kết thúc bình thường" xuất hiện, toàn bộ không gian mẫu rơi qua và tự động in (vì không có tùy chọn -n) ... gọn gàng! .. +1
Peter.O

@fred: nhờ tôi nghĩ rằng tôi bắt đầu hiểu sed quá, nó cung cấp các công cụ chỉnh sửa tốt đẹp cho nhiều dòng nhưng làm thế nào để tình trạng lộn xộn họ để có được những gì bạn cần là không đơn giản và cũng không dễ đọc là ở đầu ...
neurino

Cẩn thận với kết thúc dòng DOS, aka. vận chuyển trở lại hoặc \ r!
dùng77376

1
Có chuyện gì vớised -e :a -e '/\\$/N; s/\\\n//; ta'
Isaac

18

Nó có thể dễ nhất với perl (vì perl giống như sed và awk, tôi hy vọng nó được bạn chấp nhận):

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

ngắn gọn và đơn giản, tôi thích cái đó +1 Và anh ấy không yêu cầu sed hay awk một cách rõ ràng
rudolfson


2

Đây không phải là một câu trả lời như vậy. Đây là một vấn đề phụ về sed.

Cụ thể, tôi cần phải sedtách từng lệnh Gilles để hiểu nó ... Tôi bắt đầu viết một số ghi chú về nó, và sau đó nghĩ rằng nó có thể hữu ích ở đây cho ai đó ...

Vì vậy, đây là ... kịch bản sed của Gilles ở định dạng tài liệu :


#!/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
Giải pháp của Neurino thực sự khá đơn giản. Nói về sed nhẹ phức tạp, điều này có thể bạn quan tâm .
Gilles 'SO- ngừng trở nên xấu xa'

2

Tuy nhiên, một công cụ dòng lệnh phổ biến khác sẽ là ed, theo mặc định sửa đổi các tệp tại chỗ và do đó để lại các quyền của tệp không được sửa đổi (để biết thêm thông tin về việc edxem Chỉnh sửa tệp bằng trình soạn thảo văn bản ed từ các tập lệnh )

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

Sử dụng thực tế là readtrong trình bao sẽ giải thích dấu gạch chéo ngược khi được sử dụng mà không có -r:

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

Lưu ý rằng điều này cũng sẽ diễn giải bất kỳ dấu gạch chéo ngược nào khác trong dữ liệu.


Không. Nó sẽ không loại bỏ tất cả dấu gạch chéo ngược. Hãy thử vớia\\b\\\\\\\\\\\c
Isaac

@Isaac Ah, có lẽ tôi nên nói "diễn giải bất kỳ dấu gạch chéo ngược nào khác"?
Kusalananda

1

Một giải pháp (r) đơn giản tải toàn bộ tệp trong bộ nhớ:

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

Hoặc một dòng ngắn vẫn hoạt động để hiểu (đầu ra) dòng (cú pháp GNU):

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

Trên một dòng (cú pháp POSIX):

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

Hoặc sử dụng awk (nếu tệp quá lớn để vừa trong bộ nhớ):

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

0

Phiên bản Mac dựa trên giải pháp @Giles sẽ như thế này

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

Trường hợp khác biệt chính là cách các dòng mới được thể hiện và kết hợp thêm bất kỳ dòng nào vào một dòng sẽ phá vỡ nó


-1

Bạn có thể sử dụng cpp, nhưng nó tạo ra một số dòng trống trong đó nó hợp nhất đầu ra và một số giới thiệu mà tôi loại bỏ với sed - có thể nó cũng có thể được thực hiện với cpp-flags và các tùy chọn:

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

Bạn có chắc cpp một giải pháp? Trong ví dụ của bạn, echochuỗi có dấu ngoặc kép đã cho ra văn bản thẳng, vì vậy cpplà vô nghĩa. (Điều này cũng áp dụng cho sedmã của bạn .) Nếu bạn đặt chuỗi trong dấu ngoặc đơn, cppchỉ cần loại bỏ dấu gạch chéo ngược nhưng không nối các dòng. (Việc kết hợp với cppsẽ hoạt động nếu không có khoảng trống trước dấu gạch chéo ngược, nhưng sau đó các từ riêng biệt sẽ được nối mà không có dấu phân cách.)
manatwork

@manatwork: Outsch! :) Tôi đã rất ngạc nhiên, rằng lệnh sed đã hoạt động, nhưng tất nhiên, đó không phải là lệnh sed, mà chính bash diễn giải dấu gạch chéo ngược là sự tiếp nối của dòng trước đó.
người dùng không xác định

Sử dụng cppnhư thế vẫn không nối các dòng cho tôi. Và việc sử dụng sedchắc chắn là không cần thiết. Sử dụng cpp -P: Tạo -Pức chế tạo linemarkers trong đầu ra từ bộ tiền xử lý.
Trực tiếp

Lệnh của bạn không làm việc cho tôi: 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 filesMột cpp --versiontiết lộ cpp (Ubuntu 4.4.3-4ubuntu5.1) 4.4.3- cái gì? Ubuntu đang vá cpp? Tại sao? Tôi dự kiến ​​sẽ đọc GNU ...
người dùng không xác định

Hấp dẫn. Ubuntu cppthực sự nối các dòng và để lại một số khoảng trống. Thậm chí thú vị hơn, cùng một phiên bản 4.4.3-4ubfox5.1 ở đây chấp nhận -P. Tuy nhiên, nó chỉ loại bỏ các linemarkers, các dòng trống vẫn còn.
manatwork
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.