awk + in tất cả nội dung dòng trừ $ 1


4

Tôi viết kịch bản awk đang theo dõi:

% echo /var/sysconfig/network/my_functions  alpha beta gama  | \
      awk -v word=alpha '$2  == word { print $0 }'

Làm thế nào để nói với awk rằng tôi muốn in tất cả các dòng ngoại trừ $ 1 (/ var / sysconfig / network / my_fifts PATH) để tôi sẽ nhận được những điều sau:

alpha beta gama

thay vì

/var/sysconfig/network/my_functions alpha beta gama

nhận xét : nội dung dòng có thể là bất cứ điều gì và không giới hạn bởi số lượng chuỗi / từ

Câu trả lời:


1

Tôi nghĩ rằng trong awk không có cách nào ngoài việc loại bỏ trường đầu tiên bằng tay. (Có nhiều cách khác nếu bạn sẵn sàng bình thường hóa không gian liên trường.)

awk '$2 == word {match($0, "("FS")+"); print substr($0, RSTART+RLENGTH);}'

Lưu ý rằng, nếu có khoảng trắng trước đó $1, giải pháp này sẽ loại bỏ khoảng trắng hàng đầu đó và để lại tất cả các trường (bao gồm $1). Không có bất kỳ đề nghị nào trong câu hỏi điều đó có thể xảy ra.
Scott

5

Nếu bạn đặt $1thành ""bạn sẽ rời khỏi không gian phân định. Nếu bạn không muốn làm điều đó, bạn phải lặp đi lặp lại trên các lĩnh vực:

awk '{for (f=2; f<=NF; ++f) { if (f!=2) {printf("%s",OFS);} printf("%s",$f)}; printf "\n" }'

Chỉnh sửa: cố định theo nhận xét của Gilles.

Một cách khác để làm điều tương tự:

awk '{d = ""; for (f=2; f<=NF; ++f) {printf("%s%s", d, $f); d = OFS}; printf("\n") }'

Errrm, điều này in các trường trên các dòng riêng biệt (sau s / $NF/ NF/). Bạn có thể sử dụng if (f!=2) {printf("%s",OFS);} printf("%s",$f);như cơ thể vòng lặp.
Gilles

@Gilles: Rất tiếc, tôi đã quá vội vàng.
Dennis Williamson

Xét đề nghị thứ hai cần phải bắt đầu bằng cách đặt lại dđể ""; như đã viết, nó sẽ chỉ hoạt động như dự định cho dòng đầu tiên.
dubiousjim

@dubiousjim: Cảm ơn, tôi đã sửa câu trả lời của mình.
Dennis Williamson

Ngoài ra, nếu có nhiều khoảng trắng (hoặc tab) giữa bất kỳ trường nào (ví dụ alpha  beta      gama:), điều này sẽ thay thế chúng bằng các khoảng trắng đơn ( alpha beta gama). Không phải là OP thể hiện một yêu cầu để duy trì khoảng trắng giữa các trường.
Scott

2

Bằng cách nào đó tôi nghĩ rằng điều này sẽ dễ dàng hơn nhiều và trực quan hơn để thực hiện với lệnh cắt:

echo /var/sysconfig/network/my_functions  alpha beta gama | cut -d' ' -f 2-

Vấn đề duy nhất là cắt không hỗ trợ nhiều loại khoảng trắng khác nhau cùng một lúc cho các dấu phân cách. Vì vậy, nếu bạn có khoảng trắng hoặc tab, nó sẽ không hoạt động.


Điều đó sẽ không hoạt động nếu trường đầu tiên thay đổi chiều dài.
Dennis Williamson

2
@Dennis: Vâng, nó sẽ. Nó sẽ không hoạt động nếu dấu phân cách trường đầu tiên thay đổi theo chiều dài (hoặc sử dụng tab), như deltaray đã viết.
Gilles

@Gilles: Tôi đoán tôi chỉ không bao giờ sử dụng cutngoại trừ dữ liệu chiều rộng cố định.
Dennis Williamson

@Dennis, có lẽ bạn đang nghĩ đến tùy chọn -c để cắt, đó là cắt dựa trên các ký tự. -f là dành cho các lĩnh vực. Tôi muốn cắt giảm mạnh hơn một chút như awk với chiều dài dải phân cách, bởi vì nó nhanh hơn để sử dụng cho những thứ như thế này.
deltaray

1
 % echo /var/sysconfig/network/my_functions  alpha beta gama | \
      awk -v word=alpha \
             '$2 == word { $1=""; print $0 }'

2
Với sự cảnh báo đã được quan sát bởi Dennis rằng điều này rời khỏi khoảng trắng trước đó $2.
Gilles

(Một số chiêu hồn ở đây, nhưng chủ đề này hiện lên trong những câu hỏi tích cực chỉ là bây giờ): Khoảng trắng thêm có thể được cắt với ví dụ cutnhư trong awk -v word=alpha '$2==word {$1=""; print}' | cut -b2-(nếu áp phích không muốn sử dụng cuttrực tiếp như trong câu trả lời deltaray, nhưng thiếu các lựa chọn trên Phần "$ 2" (có thể được sửa bằng grepthay vì awk)).
Daniel Andersson

1

Giải pháp (hơi phức tạp) này, hơi giống với câu trả lời của Gilles ,

  • không có khoảng trống ở đầu dòng
  • xử lý chính xác trường hợp dòng đầu vào bắt đầu bằng khoảng trắng và
  • bảo tồn khoảng trắng giữa các lĩnh vực.
awk -v word=alpha '
    $2 == word {
        i = index($0, $1)               # Find $1 within $0 (the line).
        if (i > 0) {                    # Sanity check; should always be true.
                i = i + length($1)      # Find space after $1.
                temp = substr($0, i)
                i = index(temp, $2)     # Find $2 in remainder of line.
                if (i > 0) {            # Sanity check; should always be true.
                        print substr(temp, i)
                }
        }
    }'

Tôi tin rằng các ý kiến ​​nội tuyến giải thích nó khá tốt. Chúng tôi tìm thấy $1 vị trí của hàng trong dòng (hãy nhớ rằng, tôi rõ ràng không cho rằng đó là lúc bắt đầu). Sau đó, câu trả lời của à la Gilles , chúng tôi loại bỏ $1(và khoảng trắng trước nó, nếu có) ra khỏi dòng. Sau đó tìm $2vị trí của phần còn lại của dòng và loại bỏ khoảng trắng trước đó.


Đây là một chút tinh giản câu trả lời của Dennis Williamson .

awk -v word=alpha '$2==word { for (f=2; f<=NF; ++f) printf("%s%s", $f, (f==NF?ORS:OFS)) }'

Giống như câu trả lời của Dennis, nó sẽ tạo ra các lĩnh vực $2, $3, ..., $NF(bỏ qua $1) với tách mặc định. Dennis đã tiếp cận các phần trước $3, trên, $NF(nhưng không $2) với dấu tách trường đầu ra mặc định. Tôi đã sử dụng cách tiếp cận sau $2 , trên $3, $(NF-1)(nhưng không $NF) với OFS. Và, do $NF được phân tách bằng dấu tách bản ghi đầu ra (ORS), chúng ta có thể sử dụng một ?:toán tử không có thuật ngữ null và loại bỏ phần cuối cùng printf("\n").



-1

Sử dụng điều này nếu bạn muốn thay đổi dấu phân cách. Dấu phân cách của tôi là "|":

awk -F '|' '{d = ""; for (f=2; f<=NF; ++f) {printf("%s%s", d, $f); d = OFS}; printf("\n") }'

1
(1) Đây là một biến thể nhỏ trong câu trả lời của Dennis Williamson . Nếu bạn sao chép câu trả lời của người khác, thậm chí để cải thiện nó, bạn nên cung cấp tín dụng cho nguồn. (2) Tôi tin rằng điều này không thực sự đóng góp đủ thông tin mới để biện minh cho một câu trả lời riêng biệt. Những điều như thế này có lẽ nên được bình luận. Một khi bạn có đủ danh tiếng, bạn sẽ có thể nhận xét về bất kỳ bài đăng nào . Tiết (Cont'd)
Scott

(Tiếp theo) Tôi nhận ra rằng bạn không có tiếng tăm để làm điều đó, vì vậy hãy kiếm nó, và sau đó làm điều đó. (3) Đặt dấu tách trường thường hữu ích, nhưng không thực sự phù hợp với câu hỏi này. Cụ thể, câu trả lời của bạn không đầy đủ vì nó không đặt dấu tách trường đầu ra khớp với dấu tách trường đầu vào, vì vậy lệnh của bạn sẽ không bao giờ tạo ra dòng đầu vào với trường đầu tiên bị loại bỏ.
Scott

Cảm ơn đã sửa chữa, tôi chỉ học kịch bản shell nên tôi không bận tâm đến việc cung cấp tín dụng cho Dennis :), dù sao cũng cảm ơn vì đã sửa lỗi cho tôi - bất cứ ai đang quản lý điều này đều có thể xóa bài đăng của tôi nếu điều này là thừa và không giúp được gì cho người khác. Cảm ơn và chúc may mắn !!
Dhaulakhandi

Tôi đánh giá cao tất cả những người đang đăng bài trong stackover vì điều này đã giúp ích rất nhiều lần trong suốt sự nghiệp của tôi :), Cảm ơn nhà phát minh và những người tham gia.
Dhaulakhandi
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.