Cách thay thế văn bản trong một cột


7

Tôi có một tệp rất lớn (hơn 2 GB) trong đó dữ liệu giống như bên dưới.

12,324,32342,E:fsdsf,23432,34534,45345,324

13,3224,342,E:werwefsdsf,23432,34534,45345,324

121,3244,33442,E:,23432,34534,45345,324

Ở đây tôi cần thay thế tất cả các lần xuất hiện của cột thứ 4 bất cứ nơi nào nó gặp phải E:với một khoảng trắng "", nhưng bất cứ nơi nào nó tìm thấy một chuỗi sau E:đó, nó sẽ vẫn như cũ.

Sản lượng dự kiến ​​sẽ là:

12,324,32342,E:fsdsf,23432,34534,45345,324

13,3224,342,E:werwefsdsf,23432,34534,45345,324

121,3244,33442,,23432,34534,45345,324

Tôi đã thử dưới đây - awk -F, '{if ($ 4 = "E:") $ 4 = "";} 1' OFS =, data.final nhưng điều này sẽ thay thế tất cả các lần xuất hiện của $ 4 bằng một khoảng trắng.
anurag

Câu trả lời:


8

Cú pháp của bạn gần như đúng. Để kiểm tra sự bằng nhau của chuỗi awk, sử dụng dấu bằng kép : ==. Để gán một giá trị , sử dụng một dấu bằng duy nhất.

Vì vậy, sử dụng if ($4 == "E:")và bạn sẽ nhận được kết quả bạn muốn.

Lệnh đầy đủ sẽ trông như thế này. Lưu ý rằng chỉ có một sự khác biệt về ký tự so với lệnh bạn đã sử dụng; đó là lỗi duy nhất của bạn:

awk -F , '{ if ($4 == "E:") $4="";}1' OFS=, data.final

Để hiển thị một số cú pháp khác nhau và các cách tiếp cận khác nhau, các phiên bản sau đây hoàn toàn tương đương:

awk -F, -v OFS=, '$4 == "E:" { $4 = "" }; 1' data.final

awk 'BEGIN { FS=OFS="," }; $4 == "E:" { $4 = "" }; {print}' data.final

awk -F, -v OFS=, '{sub( /^E:$/, "", $4); print}' data.final

Những lưu ý liên quan đến vấn đề trên:

  1. Nếu toàn bộ khối mã của bạn chỉ là if / then, bạn chỉ có thể sử dụng điều kiện làm bộ lọc cho khối mã. Do đó $4 == "E:" {$4 = ""}chính xác tương đương với{if ($4 == "E:") {$4 = ""}}
  2. Đó là một thực hành tốt để gửi các câu lệnh "sau đó" trong một khối mã ngay cả khi chỉ có một trong số chúng, if ($4 == "E:") {$4 = ""}chứ không phải làif ($4 == "E:") $4 = "";
  3. -Fđặt giá trị của FS-vcó thể được sử dụng để đặt giá trị của bất kỳ biến nào trước khi awkxem xét dòng đầu tiên của tệp đầu tiên. (Bạn có thể biết điều đó.) Bạn cũng có thể sử dụng một BEGINkhối để làm điều tương tự; đáng để biết khi bạn muốn làm cho awkkịch bản độc lập.
  4. Lý do tại sao 1in các dòng trong awkđó là một điều kiện (bộ lọc) luôn luôn đánh giá là đúng và hành động mặc định awkkhi không có khối mã nào được gắn vào bộ lọc print $0. Vì vậy, 1bản thân nó là tương đương 1 {print}hoặc 1 {print $0}hoặc chỉ {print}.
  5. Trong biến thể cuối cùng của tôi, tôi đã sử dụng một subhàm để thay thế regex /^E:$/(bắt đầu chuỗi E:, cuối chuỗi) bằng ""in $4.

subhàm trả về số lần thay thế đã được thực hiện (1 hoặc 0; sử dụng gsubđể thực hiện nhiều thay thế), bạn có thể mã hóa vấn đề này bằng cách thêm một vào subkết quả hàm để đảm bảo bạn có một mẫu luôn luôn đúng dòng kết quả được in cho dù thay thế được thực hiện hay không. Đây là phiên bản mã golf, không được khuyến nghị cho người mới bắt đầu sử dụng nếu bạn đặt mã này vào tập lệnh sau đó bạn sẽ duy trì:

awk -F, -v OFS=, 'sub(/^E:$/,"",$4)+1' data.final

:)


2

Với sed:

sed -r 's/^([^,]+,[^,]+,[^ ]+,)E:(,)/\1\2/' file.txt

Trường được phân tách bằng dấu phẩy thứ 4 sẽ được làm trống nếu chỉ chứa E:.

Thí dụ:

% cat file.txt
12,324,32342,E:fsdsf,23432,34534,45345,324
13,3224,342,E:werwefsdsf,23432,34534,45345,324
121,3244,33442,E:,23432,34534,45345,324

% sed -r 's/^([^,]+,[^,]+,[^ ]+,)E:(,)/\1\2/' file.txt 
12,324,32342,E:fsdsf,23432,34534,45345,324
13,3224,342,E:werwefsdsf,23432,34534,45345,324
121,3244,33442,,23432,34534,45345,324

s tream ed itor +1
Pandya

0

Giả sử tên tệp của bạn là file, bạn có thể thử như sau:

while read -r line; 
do 
var="$(echo "$line" | cut -d ',' -f 4)";

  if [[ "$var" = "E:" ]]; then echo "$line" | sed s/"$var"/''/g ; 
  else echo "$line";
  fi; 

done < file

hoặc là:

while read -r line; do var="$(echo "$line" | cut -d ',' -f 4)"; if [[ "$var" = "E:" ]]; then echo "$line" | sed s/"$var"/''/g ; else echo "$line";fi; done < file

Giải trình:

  1. while read -r line; đọc từng dòng tệp
  2. var="$(echo "$line" | cut -d ',' -f 4)";lở loét chuỗi ở vị trí thứ 4 cách nhau bởi ,biếnvar
  3. if [[ && "$var" = "E:" ]]; then echo "$line" | sed s/"$var"/' '/g ;nếu $varcó chuỗi chính xác E:thì sed s/"$var"/''/g ;thay thế nó bằng trống""
  4. else echo "$line"; khôn ngoan khác nó in dòng như nó là

Ví dụ đầu ra (như mong đợi từ câu hỏi):

  • file:

    $ cat file
    12,324,32342,E:fsdsf,23432,34534,45345,324
    
    13,3224,342,E:werwefsdsf,23432,34534,45345,324
    
    121,3244,33442,E:,23432,34534,45345,324
    
  • Chạy lệnh:

    $ while read -r line; do var="$(echo "$line" | cut -d ',' -f 4)"; if [[ "$var" = "E:" ]]; then echo "$line" |sed s/"$var"/' '/g ; else echo "$line";fi; done < file
    12,324,32342,E:fsdsf,23432,34534,45345,324
    
    13,3224,342,E:werwefsdsf,23432,34534,45345,324
    
    121,3244,33442,,23432,34534,45345,324
    

Bạn cũng có thể chuyển hướng đầu ra của mình thành tệp bằng cách sử dụng >> file2hoặc |tee file2ở cuối lệnh:

while read -r line; do var="$(echo "$line" | cut -d ',' -f 4)"; if [[ "$var" = "E:" ]]; then echo "$line" |sed s/"$var"/' '/g ; else echo "$line";fi; done < file | tee file2
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.