Có hai cách tiếp cận cơ bản người ta có thể sử dụng khi xử lý các trường: i) sử dụng một công cụ hiểu các trường; ii) sử dụng biểu thức chính quy. Trong hai, trước đây thường mạnh mẽ hơn và đơn giản hơn.
Nhiều công cụ phổ biến có sẵn trên * nix được thiết kế rõ ràng để xử lý các trường hoặc có các thủ thuật tiện lợi để tạo điều kiện thuận lợi cho nó.
1. Sử dụng một công cụ hiểu các lĩnh vực
1.1
Công cụ cổ điển ở đây là awk
. Nó sẽ tự động tách mỗi dòng đầu vào vào các lĩnh vực (tách lĩnh vực là khoảng trắng theo mặc định nhưng có thể được thay đổi bằng cách sử dụng -F
lá cờ) và các lĩnh vực này sau đó được sẵn sàng cho awk
kịch bản như nơi là số lĩnh vực. Trường thứ 1 là , trường thứ hai, v.v.$n
n
$1
$2
Dòng in có trường thứ 3 là foo
.
awk '$3=="foo"' file
Thay đổi dấu phân cách thành :
awk -F":" '$3=="foo"' file
Hành động mặc định awk
là in. Do đó, các lệnh trên sẽ in tất cả các dòng có trường thứ 3 foo
. Khi sử dụng -F
, bạn có thể đặt các dấu tách trường tùy ý và thậm chí sử dụng các biểu thức thông thường.
Làm cách nào tôi chỉ có thể in các dòng có trường thứ 3 không foo
?
awk '$3!="foo"' file
Làm cách nào tôi chỉ có thể in các dòng có trường thứ 3 khớp foo
?
Nếu bạn chỉ tìm kiếm các trường khớp với một mẫu (ví dụ: foo
khớp foobar
), hãy sử dụng ~
thay vì ==
:
awk '$3~/foo/' file
Làm cách nào tôi chỉ có thể in các dòng có trường thứ 3 không khớp foo
?
awk '$3!~/foo/' file
Làm cách nào để thay đổi trường thứ 3 thành foo
?
awk '$3="foo"' file
1,2 Perl
Một sự lựa chọn khác là perl
một lớp lót. Giống như awk, Perl là một ngôn ngữ kịch bản đầy đủ tính năng nhưng cũng có thể được chạy như một chương trình dòng lệnh lấy kịch bản làm đầu vào. Hành vi của nó được sửa đổi bằng các công tắc dòng lệnh, liên quan nhất đến câu hỏi này là:
-e
: tập lệnh perl
nên chạy;
-n
: đọc dòng tệp đầu vào theo dòng;
-p
: in từng dòng đầu vào sau khi áp dụng tập lệnh được cung cấp bởi -e
;
-l
: xóa các dòng mới theo dõi từ mỗi dòng đầu vào và thêm một dòng mới vào mỗi print
cuộc gọi;
-a
: awk-mode, chia từng dòng đầu vào thành mảng @F
;
-F
: dấu phân cách trường cho -a
.
Một sự khác biệt quan trọng awk
là công tắc perl
của nó -a
chia các tệp thành một mảng. Trong Perl, mảng bắt đầu từ 0, không phải 1. Điều này có nghĩa là trường thứ 2 thực sự $F[1]
và không $F[2]
. Với tất cả những điều này, perl
tương đương với những điều trên là:
Dòng in có trường thứ 3 là foo
.
perl -ane 'print if $F[2] eq "foo"' file
Thay đổi dấu phân cách thành :
perl -F":" -ane 'print if $F[2] eq "foo"' file
Không giống như awk
, perl
không thể sử dụng biểu thức chính quy làm dấu phân cách trường. Họ cần phải là một nhân vật hoặc chuỗi cụ thể.
Làm cách nào tôi chỉ có thể in các dòng có trường thứ 3 không foo
?
perl -ane 'print unless $F[2] eq "foo"' file
Làm cách nào tôi chỉ có thể in các dòng có trường thứ 3 khớp foo
?
perl -ane 'print if $F[2]=~/foo/' file
Làm cách nào tôi chỉ có thể in các dòng có trường thứ 3 không khớp foo
?
perl -lane 'print unless $F[2]=~/foo/' file
Làm cách nào để thay đổi trường thứ 3 thành foo
?
Điều này là một chút rườm rà hơn trong Perl. Cách tiếp cận thông thường là thay đổi giá trị trong @F
mảng và sau đó in mảng. Với các tệp được phân tách bằng dấu cách đơn giản, điều này thật dễ dàng:
perl -lane '$F[2]="foo"; print "@F"' file
Với một dấu phân cách khác, bạn sẽ cần đến join
mảng. Nếu không, nó sẽ được in tách biệt không gian:
perl -F: -lane '$F[2]="foo"; print join ":",@F' file
2. Sử dụng biểu thức chính quy
Ý tưởng ở đây là sử dụng một biểu thức chính quy (viết tắt là "regex") để xác định vị trí của chuỗi mục tiêu trong dòng. Ví dụ: trong một tệp có các trường được phân tách bằng nhau :
, chúng ta có thể tìm trường thứ 2 bằng cách khớp mọi thứ với trường thứ 1 :
(trường thứ 1) và sau đó tìm kiếm trường thứ hai:
^[^:]*:[^:]*:
Regex này có nghĩa là:
^
: đầu dòng;
[^]
: một lớp nhân vật phủ định. [^:]
có nghĩa là "bất cứ điều gì nhưng :
";
*
: 0 hoặc nhiều hơn mẫu trước đó;
:
: một nghĩa đen :
;
Được kết hợp với nhau, điều này có nghĩa là trường đầu tiên [^:]*
là trường thứ nhất và trường thứ hai là trường thứ hai. Rõ ràng, điều này không thực tế lắm nếu bạn đang tìm kiếm trường thứ 14 nhưng nó có thể hữu ích cho những điều đơn giản hơn. Vì vậy, làm thế nào để chúng tôi thực hiện điều này để thao túng dữ liệu của chúng tôi? Có nhiều công cụ khác nhau có thể làm điều này; trong những ví dụ này tôi sẽ sử dụng sed
nhưng bạn có thể làm những việc rất giống với awk
, perl
hoặc python
.
Làm cách nào tôi chỉ có thể in các dòng có trường thứ 2 foo
?
sed -n '/^[^:]*:foo:/p' file
Việc -n
loại bỏ đầu ra bình thường và /regex/p
có nghĩa là "in bất kỳ dòng nào mà biểu thức chính quy phù hợp.
Làm cách nào tôi chỉ có thể in các dòng có trường thứ 2 không foo
?
sed '/^[^:]*:foo:/d' file
Các nghịch đảo logic của ở trên. Ở đây, /regex/d
có nghĩa là "xóa bất kỳ dòng nào mà regex khớp.
Làm cách nào tôi chỉ có thể in các dòng có trường thứ 2 khớp foo
?
sed -n '/^[^:]*:[^:]*foo/p' file
Làm cách nào tôi chỉ có thể in các dòng có trường thứ 2 không khớp foo
?
sed '/^[^:]*:[^:]*foo/d' file
Làm cách nào để thay đổi trường thứ 2 thành foo
?
sed 's/\([^:]*:\)[^:]*/\1foo/' file
Hoặc, vì sed
sự thay thế có thể trực tiếp giải quyết một sự xuất hiện của các mẫu bằng sự lặp lại của nó với một cờ số đơn giản:
sed 's/[^:]*/foo/2' file