Xóa ký tự dòng mới chỉ mỗi N dòng


16

Xử lý văn bản, tôi cần loại bỏ ký tự dòng mới mỗi hai dòng.

Văn bản mẫu:

this is line one
and this is line two
the third and the
fourth must be pasted too

Sản phẩm chất lượng:

this is line one and this is line two
the third and the fourth must be pasted too

Tôi đã thử một whilevòng lặp, nhưng một vòng lặp while là thực tế xấu. Có thể làm điều đó bằng cách sử dụng trhoặc bất kỳ lệnh nào khác?


4
Tiêu đề nói "mỗi N dòng", nhưng trong câu hỏi và ví dụ đó là "mỗi 2 dòng". Hầu hết các câu trả lời chỉ hoạt động với N = 2. Bạn đang tìm kiếm một cái gì đó làm việc cho tất cả N?
JigglyNaga

Đó là chìa khóa. Mọi người trả lời cho 2 dòng nhưng tôi sẽ cần sử dụng N = 3 hoặc N = 4
jomaweb

Câu trả lời:


24

paste(cũng là một tiện ích đơn giản POSIX tiêu chuẩn như tr) là công cụ của bạn cho điều đó.

Giả sử bạn muốn những ký tự dòng mới được thay thế bằng khoảng trắng thay vì chỉ xóa như trong mẫu của bạn:

paste -d ' ' - - < file

Hoặc là:

paste -sd ' \n' file

Thay thế ' 'bằng '\0'nếu bạn thực sự muốn loại bỏ chúng.

Để thay thế 2 trong 3:

paste -sd '  \n' file

1 trên 3, bắt đầu bằng thứ hai:

paste -sd '\n \n' file

Và như thế.

Một điều tốt nữa pastelà nó sẽ không để lại một dòng không bị chấm dứt. Chẳng hạn, nếu bạn xóa mọi dòng mới trong một tệp (như với tr -d '\n' < filehoặc tr '\n' ' ' < file), thì cuối cùng bạn không có dòng nào vì các dòng cần được chấm dứt bằng một ký tự dòng mới. Vì vậy, nói chung tốt hơn là sử dụng pastethay thế cho điều đó (như trong paste -sd '\0' filehoặc paste -sd ' ' file) sẽ thêm ký tự dòng mới đó cần thiết để có văn bản hợp lệ.


11

Với sed GNU hiện đại

sed -rz 's/\n([^\n]*\n)/ \1/g' sample.text

awk

awk '{getline line2;print $0, line2}' sample.text

3
sedCách tiếp cận đó có nghĩa là nhét toàn bộ tệp vào bộ nhớ (miễn là nó không chứa NUL byte) và thực hiện một số thay thế regrec đắt tiền. Tôi không thể thấy lợi ích của sed 'N;s/\n/ /'phương pháp tiêu chuẩn .
Stéphane Chazelas

6

Sử dụng sedcho điều này như được hiển thị dưới đây:

SHW@SHW:/tmp $ cat a
this is line one
and this is line two
the third and the
fourth must be pasted too

SHW@SHW:/tmp $ sed 'N;s/\n/ /' a -i

SHW@SHW:/tmp $ cat a
this is line one and this is line two
the third and the fourth must be pasted too

4

Một cách khác là sử dụng xargs:

$ < txt xargs -d '\n' -n 2 echo
this is line one and this is line two
the third and the fourth must be pasted too

Ở đâu

$ cat txt
this is line one
and this is line two
the third and the
fourth must be pasted too

Mặc dù, giải pháp này khá quá mức vì một echoquy trình được thực hiện cho từng dòng ... Vì vậy, bên cạnh các ví dụ về đồ chơi, nên sử dụng giải pháp dựa trên awk / sed hoặc tương tự.


1
Tùy thuộc vào echoviệc triển khai của bạn , bạn cũng sẽ gặp vấn đề với các ký tự dấu gạch chéo ngược hoặc một số dòng bắt đầu bằng -(như --helphoặc -nenevới GNU echo). Cũng lưu ý rằng đó -dlà một phần mở rộng GNU.
Stéphane Chazelas

Để tránh các vấn đề với echo, bạn có thể sử dụng điều này:< txt xargs -d '\n' -n 2 printf -- '%s %s\n'
nyuszika7h

4

Điều này thực sự cực kỳ đơn giản trong vim. Để tham gia mỗi dòng sử dụng Jlệnh, sau đó sử dụng %normlệnh để áp dụng nó cho mọi dòng đồng thời. Ví dụ

:%norm J<CR>

(Chỉ trong trường hợp bạn không quen thuộc với vim, <CR>chỉ có nghĩa là nhập)

Điều này thậm chí hoạt động để tham gia một số dòng tùy ý. Ví dụ: để tham gia cứ mười dòng sẽ là

:%norm 9J<CR>

Nếu bạn không thoải mái với vim và bạn muốn sử dụng nó như một công cụ dòng lệnh, thay vì một trình soạn thảo văn bản tương tác, bạn có thể làm:

vim myfile -c '%norm J' -c 'wq'

Downvoter có quan tâm để giải thích những gì tôi có thể làm để cải thiện câu trả lời này không?
DJMcMayhem

3
$ awk '{printf "%s%s",$0,(NR%2?" ":"\n")}' sample.txt
this is line one and this is line two
the third and the fourth must be pasted too

Điều này in ra từng dòng, $0theo sau là khoảng trắng hoặc dòng mới tùy thuộc vào số dòng NR, là số lẻ hay số chẵn.

Các biểu hiện NR%2?" ":"\n"là một tuyên bố ternary. Biểu thức NR%2ước lượng là true (khác 0) nếu số hàng là số lẻ. Trong trường hợp, biểu thức ternary trả về một khoảng trắng. Nếu nó đánh giá là sai (không), thì dòng mới được trả về.

Thay thế

Theo đề xuất của Costas trong các bình luận:

$ awk '{ORS=(NR%2?" ":RS)}1' sample.txt
this is line one and this is line two
the third and the fourth must be pasted too

Ở đây, câu lệnh ternary NR%2?" ":RSđược sử dụng để trả về khoảng trắng hoặc dấu tách bản ghi đầu vào ( RS, default = newline). Giá trị này được gán cho dấu tách bản ghi đầu ra , ORS. Phần 1cuối của lệnh là tốc ký mật mã của awk để in bản ghi.


Bạn vẫn có thể lưu 3 ký tự: ()dấu ngoặc đơn và khoảng printf
trắng

1
Chim nhạn? Oh! 'NR%2{printf("%s ",$0);next}1'
Costas

Với câu trả lời và tuyên bố tạm thời của maxschlepzig :'{ORS=(NR%2?" ":RS)}1'
Costas

@Costas Tôi thích điều đó. Trả lời cập nhật với ORSgiải pháp.
John1024

2

Giải pháp chung, thay thế 5bằng số dòng yêu cầu

$ # eof to ensure last line has newline ending
$ seq 16 | perl -pe 's/\n/ / if ++$i%5 && !eof'
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16

$ # or just use pr
$ seq 16 | pr -5ats' '
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16

1

Bạn có thể sử dụng awkcho việc này:

$ awk '{c="\n"} NR%2 {c=" "} { printf("%s%s", $0, c) } ' txt

Nó tạo ra:

this is line one and this is line two
the third and the fourth must be pasted too

Ở đâu:

$ cat txt
this is line one
and this is line two
the third and the
fourth must be pasted too

Các awkhành động được thực thi cho mỗi dòng, biến đặc biệt $0tham chiếu dòng hiện tại, NRlà số dòng hiện tại (bắt đầu từ 1). Hành động thứ hai được bảo vệ bởi biểu thức NR%2, đó là hoạt động modulo. Do đó, c=" "chỉ được thực hiện nếu NR%2là đúng, tức là cho các số dòng lẻ.

Các awkcú pháp là C như thế nào, nhưng một số yếu tố là không bắt buộc trong một số tình huống - ví dụ như dấu chấm phẩy.


cBiến của bạn là ORS:'NR%2{ORS=" "}1;{ORS=RS}'
Costas

0

Sử dụng ed:

$ cat text
this is line one
and this is line two
the third and the
fourth must be pasted too
this is line one
and this is line two
the third and the
fourth must be pasted too

$ ed text <<'END_ED'
g/./s/$/ /\
j
w text.new
END_ED
164
164

$ cat text.new
this is line one and this is line two
the third and the fourth must be pasted too
this is line one and this is line two
the third and the fourth must be pasted too

Các edlệnh chỉnh sửa sẽ, cho mỗi dòng ( gáp dụng một tập hợp các lệnh chỉnh sửa cho mỗi dòng khớp với biểu thức chính quy đã cho), thêm một ký tự khoảng trắng vào cuối và nối nó với dòng tiếp theo. Sau đó, nó viết văn bản kết quả vào một tập tin được gọi là text.new.


0

Với Ruby.

Tôi giả sử mỗi khối ndòng sẽ được tham gia. Giả sử n = 3, tệp đầu vào là 'infile'và kết quả sẽ được ghi vào tệp 'outfile'.

Xây dựng một tập tin

Ruby -e "File.write 'infile', <<_
> Line 1
> Line 2
> Line 3
> Line 4
> Line 5
> Line 6
> Line 7
> _"

Xác nhận nội dung của tập tin

ruby -e "p File.read 'infile'"
  # "Line 1\nLine 2\nLine 3\nLine 4\nLine 5\nLine 6\nLine 7\n"

Xóa dòng mới và ghi vào tệp

ruby -e "File.write 'outfile', File.readlines('infile').
  each_with_index { |line,i| line.chomp! unless (i+1)%3==0 }"

Xác nhận nội dung

ruby -e "puts File.read 'outfile'"
  # ["Line 1", "Line 2", "Line 3\n", "Line 4", "Line 5", "Line 6\n", "Line 7"]

1
Tốt một. Về lý thuyết, rubykhông có chủ đề trên U & L. Nhưng, vì bạn đang sử dụng nó từ dòng lệnh với ruby -e, điều đó làm cho nó đủ chủ đề.
hóa học
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.