Tôi nên sử dụng gì khi cắt không cắt nó?


19

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

[1598] San Diego, US (inactive)
[4517] St Louis, US (inactive)
[6346] Orlando, US (inactive)

Tôi muốn cắt tên thành phố để tôi có:

San Diego
St Louis
Orlando

Đây là điều tốt nhất tôi có thể nghĩ ra:

cut -d ',' -f1 cities | cut -d ']' -f2

Nhưng điều đó vẫn để lại cho tôi một khoảng trống trước những cái tên. Có một cutlệnh tương tự mà tôi có thể sử dụng để chấp nhận các dấu phân cách của một số ký tự để tôi có thể cắt ]không?


1
trrất hữu ích để xóa các ký tự bạn không muốn.
LawrenceC

Nếu bạn thử mã trong câu trả lời của mọi người, bạn sẽ thấy ba kết quả đầu ra khác nhau. Điều này cho thấy câu hỏi của bạn không rõ ràng 100%. "Cắt ra" có nghĩa là loại bỏ hoặc chọn? Bạn có muốn (inactive)trạng thái hay không? Vui lòng cung cấp đầu ra mẫu.
Mikel

@Mikel - Xem xét tôi đang sử dụng cutđể cắt bỏ mọi thứ và bạn có thể thấy ý định của ví dụ thất bại mà tôi có, nó sẽ khá rõ ràng trong bối cảnh. Tôi sẽ cung cấp mẫu ra mặc dù để làm rõ hơn nữa. :)
Kit Sunde

Không thật sự lắm. Tôi đã thay đổi một câu trong câu hỏi của bạn thành "chỉ in tên thành phố", vì đó là cách bạn sử dụng từ "cắt" không rõ ràng đối với tôi. Thay đổi của tôi có đúng không?
Mikel

1
@Kit Sunde: Với đầu ra mẫu, chắc chắn có thể hiểu được. Tiêu đề là dễ thương. "Cắt bỏ" khiến tôi nghĩ về những gì xảy ra khi bạn nhấn Ctrl + X, đó là lý do tại sao tôi đề xuất thay đổi, nhưng đó là câu hỏi của bạn. Downvote sẽ là ngớ ngẩn khi nó chỉ là một bất đồng đơn giản.
Mikel

Câu trả lời:


15

Awk (cũng kiểm tra Awk Info ) rất đẹp với loại câu hỏi đó. Thử:

awk -F'[],] *' '{print $2}' cities

Điều này xác định một dấu tách trường -F[],] *- có nghĩa là một lần xuất hiện của dấu ngoặc vuông đóng hoặc dấu phẩy, theo sau là 0 hoặc bất kỳ số khoảng trắng nào. Tất nhiên bạn có thể thay đổi điều đó cho phù hợp với bất kỳ yêu cầu. Đọc lên các biểu thức thông thường.

Khi dòng được phân chia, bạn có thể làm những gì bạn muốn với kết quả phân chia. Ở đây, tôi quyết định chỉ in trường thứ hai với print $2. Lưu ý rằng điều quan trọng là sử dụng các trích dẫn đơn xung quanh các hướng dẫn awk nếu không $ 2 được thay thế bằng vỏ.


2
]không phải là một khung góc. Góc ngoặc là <>. []là "ngoặc vuông" hoặc chỉ "ngoặc vuông".
cjm

Tôi nghĩ rằng bạn cần phải thoát khỏi khung đóng cửa đó, trừ khi tôi thực sự cần phải đọc lên các biểu thức thông thường của mình.
Kit Sunde

@cjm - Có thể anh ấy là người Đức: news.ycombinator.com/item?id=1181243 :)
Kit Sunde

1
@cjm, xin lỗi tôi có ý nói khung vuông, gõ hơi nhanh. @Kit, tôi không phải người Đức. Bạn không muốn thoát khỏi khung đóng bên trong (nó sẽ không phục vụ mục đích nào), nhưng nó phải là ký tự đầu tiên trong phạm vi.
asoundmove

12

Bạn có thể sửa đổi cuối cùng cuttrong đường ống của bạn để này:

cut -d ' ' -f2-

Ở trên có nghĩa là dấu tách trường là khoảng trắng và chúng tôi muốn chọn tất cả các trường bắt đầu từ giây. Chuỗi hoàn chỉnh trở thành:

cut -d ',' -f1 cities | cut -d ' ' -f2-

12

Để phân tích cú pháp phức tạp hơn, bạn nên sử dụng sed (1) :

sed -e 's/\[[0-9]\+\] \([^,]\+\),.*/\1/' cities

Hoặc sử dụng -rđể đơn giản hóa biểu thức chính quy, như được đề xuất bởi pepoluan :

sed -re 's/\[[0-9]+\] ([^,]+),.*/\1/' cities

2
+1. bạn cũng có thể sử dụng -r để tránh thoát các ký tự regex nâng cao, đơn giản hóa rất nhiều mẫu regex
pepoluan

0

Tôi thường sử dụng Perl khi mọi thứ trở nên quá khó khăn cho sed và grep.

Có một số cách bạn có thể viết nó trong Perl. Ví dụ: bạn có thể thích nó nhanh hơn hoặc bạn có thể thích nó để xử lý các sự cố không mong muốn nhỏ trong đầu vào (ví dụ: hai khoảng trống nơi một dự kiến).

Một cách rõ ràng (giả sử id là số, thành phố là chữ cái, trạng thái là chữ cái):

while (<>) {
    if (/^\[\d+\] (\w+(?: \w+)*), \w+ \(\w*\)$/) {
        my $city = $1;
        print "$city\n";
    }
}

Hoặc chậm hơn nhưng dễ dãi hơn (quay lại nhiều hơn):

while (<>) {
    if (/^.*\]\s+(.*),.*$/) {
        my $city = $1;
        print "$city\n";
    }
}

Hoặc nhanh hơn (trường dừng tại lần xuất hiện đầu tiên của khung đóng):

while (<>) {
    if (/^\[[^]]*\] ([^,]*), \S+ \([^)]*\)$/) {
        my $city = $1;
        print "$city\n";
    }
}

Từ dòng lệnh thay vì tập lệnh, bạn có thể sử dụng -ntùy chọn, về cơ bản sẽ thêm while (<>) { BLOCK }vòng lặp:

perl -ne '/^\[[^]]*\] ([^,]*), \S+ \([^)]*\)$/ and print $1, "\n";' cities

hoặc nếu bạn muốn cách sử dụng giống với cắt, bạn có thể sử dụng -Ftùy chọn, tương tự như -Ftùy chọn của awk , ví dụ:

perl -a -n -F'/[],]\s+/' -e 'print $F[1], "\n"' cities

Cách này rõ ràng giả định rằng không có trường nào sẽ chứa bất kỳ dấu phân cách nào.

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.