Làm thế nào để in cột đầu tiên của dòng tiếp theo trong dòng hiện tại?


8

Tôi có một số tập tin như thế này:

abc 123    
abc 789  
bcd 456  
acb 135

Tôi muốn in cột đầu tiên của dòng tiếp theo trong dòng hiện tại.

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

abc  123 abc  
abc 789 bcd  
bcd 456 acb  
acb 135 

Tôi thích sử dụng awk.

Câu trả lời:


16

Ghi nhớ dòng trước:

awk 'NR > 1 { print prev, $1 } { prev = $0 } END { print prev }'

Quá trình này xử lý đầu vào như sau:

  • nếu dòng hiện tại là dòng thứ hai trở lên, hãy in dòng trước đó (được lưu trữ prev, xem bước tiếp theo) và trường đầu tiên của dòng hiện tại, được phân tách bằng dấu tách trường đầu ra (ký tự khoảng trắng theo mặc định);
  • trong mọi trường hợp, lưu trữ dòng hiện tại trong prevbiến;
  • ở cuối tập tin, in dòng trước.

11

Phương awkpháp thay thế :

$ awk 'NR == 1{printf "%s", $0;next}{printf " %s\n%s", $1,$0}' input.txt                                    
abc 123 abc
abc 789 bcd
bcd 456 acb
acb 135

Cách thức hoạt động này rất đơn giản: dòng đầu tiên là trường hợp đặc biệt - chúng tôi in nó mà không có dòng mới và bảo awk đi đến dòng tiếp theo mà không thực hiện các khối mã khác. Sau đó, NR == 1{printf "%s", $0;next}được bỏ qua, nhưng các phần khác làm công việc.

Hãy nhớ rằng cho đến nay chúng tôi đã in một chuỗi được định dạng mà không có ký tự dòng mới. Do đó, những gì đang được thực hiện printf " %s\n%s",$1,$0bây giờ là từ đầu tiên được in ra (và vì không có dòng mới, nó vẫn nằm trên cùng một dòng đầu ra), dòng mới được chèn, và sau đó toàn bộ dòng (nhưng không kết thúc bằng ký tự dòng mới) . Do đó, từ đầu tiên tiếp theo được chèn sẽ vẫn nằm trên cùng một dòng. Quá trình tiếp tục và tiếp tục cho đến khi chúng tôi đạt đến cuối tập tin.

Cải tiến có thể là bao gồm END{print ""}khối để chèn dòng mới cuối cùng. Trong một số trường hợp trong đó tệp kết quả sẽ được xử lý bởi các tập lệnh khác, nó có thể được mong muốn.


Mặc dù người dùng yêu cầu AWK một cách cụ thể, ví dụ, cách tiếp cận tương tự với việc in các chuỗi được định dạng có thể được thực hiện với các ngôn ngữ khác, ví dụ như Python. Python thay thế được cung cấp cho những người tò mò về cách thực hiện điều này bằng các ngôn ngữ khác:

#!/usr/bin/env python
from __future__ import print_function
import sys

old = None
for index,line in enumerate(sys.stdin):
    if index == 0:
        print(line.strip(),end=" ")
        continue
    words = line.strip().split()
    print(words[0] + "\n" + line.strip(),end=" ")

Và cách sử dụng như vậy:

$ ./append_first.py < input.txt                            
abc 123 abc
abc 789 bcd
bcd 456 acb
acb 135

Ý tưởng tương tự về dòng mới cuối cùng áp dụng ở đây.


9

Đây là một sedcách xấu xí chỉ để cho vui

sed '2,$ s/[^ ]\+/& &/; 2,$ s/ /\n/' file | paste -d ' ' - -
abc 123 abc
abc 789 bcd
bcd 456 acb
acb 135 

Giải trình

  • 2,$ từ dòng thứ hai đến dòng cuối cùng
  • s/[^ ]\+/& &/ nhân đôi bộ ký tự không khoảng trắng đầu tiên
  • ; tách các lệnh, như trong shell
  • s/ /\n/ thay thế không gian đầu tiên bằng một dòng mới
  • paste -d ' ' - - dính mớ hỗn độn này lại với nhau (nối dòng thứ hai vào dòng thứ ba, dòng thứ tư với dòng thứ ba, v.v.)

1
Ngoài ra, bạn có thể sedtự mình sử dụng mà không cần paste:sed -r 'N;s/\n(\w+)/\1&/;P;D' somefile.txt
Chấn thương kỹ thuật số

1
Nếu bạn viết sedchương trình cho vui, thì có lẽ bạn nên chơi code-golf ;-)
Chấn thương kỹ thuật số

1
@DigitalTrauma cô ấy đã chơi golf được 2 tháng rồi;)
Sergiy Kolodyazhnyy

1

Theo tôi cách tiếp cận đơn giản và dễ đọc nhất là:

  1. trích xuất cột đầu tiên ( cut)
  2. xóa dòng đầu tiên khỏi cột trích xuất của bạn ( tail)
  3. dán cột này vào tệp nguồn của bạn ( paste)

Ví dụ: tệp inpult mẫu của bạn:

abc 123    
abc 789  
bcd 456  
acb 135

Sau đó chạy lệnh sau trong một thiết bị đầu cuối

cut -d' ' -f1 in.txt | tail -n +2 | paste -d' ' file -

Đầu ra:

abc 123 abc
abc 789 bcd
bcd 456 acb
acb 135

Cấu trúc đằng sau giải pháp này khác với các câu trả lời đã cho. Không cần điều kiện, vòng lặp hoặc biểu thức chính quy.

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.