Làm thế nào để thực hiện lệnh 'cắt' đối xử với các dấu phân cách liên tiếp như một?


309

Tôi đang cố trích xuất một trường (thứ tư) nhất định từ luồng văn bản được điều chỉnh theo 'không gian' dựa trên cột. Tôi đang cố gắng sử dụng cutlệnh theo cách sau:

cat text.txt | cut -d " " -f 4

Thật không may, cutkhông coi một số không gian là một dấu phân cách. Tôi có thể đã đi qua awk

awk '{ printf $4; }'

hoặc sed

sed -E "s/[[:space:]]+/ /g"

để thu gọn các không gian, nhưng tôi muốn biết liệu có cách nào để giải quyết cutvà một số dấu phân cách nguyên bản không?


12
AWK là con đường để đi.
Tạm dừng cho đến khi có thông báo mới.

Câu trả lời:


546

Thử:

tr -s ' ' <text.txt | cut -d ' ' -f4

Từ trtrang người đàn ông:

-s, --squeeze-lặp lại thay thế từng chuỗi đầu vào của một ký tự lặp lại
                        được liệt kê trong SET1 với một lần xuất hiện
                        của nhân vật đó

24
Không cần catở đây. Bạn có thể chuyển < text.txttrực tiếp đến tr. vi.wikipedia.org/wiki/Cat_%28Unix%29#Usless_use_of_cat
arielf

1
Không chắc nó đơn giản hơn, nhưng bạn sẽ hợp nhất, bạn có thể từ bỏ cắt -dvà dịch thẳng từ nhiều ký tự sang tab. Ví dụ: Tôi đến đây để tìm cách tự động xuất màn hình của mình:who am i | tr -s ' ()' '\t' | cut -f5
Leo

Điều này không xóa khoảng trắng hàng đầu / dấu (có thể không muốn hoặc có thể không muốn, nhưng thường thì không), ngược lại với giải pháp awk. Giải pháp awk cũng dễ đọc hơn và ít dài dòng hơn.
n.caillou

-1 CẢNH BÁO: ĐÂY KHÔNG PHẢI LÀ CÙNG NHƯ VẬY XỬ LÝ NHỮNG NGƯỜI GIAO DỊCH YÊU CẦU NHƯ MỘT. So sánh echo "a b c" | cut -d " " -f2-,echo "a b c" | tr -s " " | cut -d " " -f2-
dùng541686

96

Khi bạn nhận xét trong câu hỏi của bạn, awkthực sự là con đường để đi. Để sử dụng cutlà có thể cùng với tr -sđể thu hẹp không gian, như câu trả lời của kev cho thấy.

Tuy nhiên, hãy để tôi đi qua tất cả các kết hợp có thể cho độc giả tương lai. Giải thích tại phần Kiểm tra.

tr | cắt

tr -s ' ' < file | cut -d' ' -f4

ôi

awk '{print $4}' file

bash

while read -r _ _ _ myfield _
do
   echo "forth field: $myfield"
done < file

quyến rũ

sed -r 's/^([^ ]*[ ]*){3}([^ ]*).*/\2/' file

Xét nghiệm

Cho tập tin này, hãy kiểm tra các lệnh:

$ cat a
this   is    line     1 more text
this      is line    2     more text
this    is line 3     more text
this is   line 4            more    text

tr | cắt

$ cut -d' ' -f4 a
is
                        # it does not show what we want!


$ tr -s ' ' < a | cut -d' ' -f4
1
2                       # this makes it!
3
4
$

ôi

$ awk '{print $4}' a
1
2
3
4

bash

Điều này đọc các lĩnh vực tuần tự. Bằng cách sử dụng, _chúng tôi chỉ ra rằng đây là biến số bỏ đi dưới dạng "biến rác" để bỏ qua các trường này. Bằng cách này, chúng tôi lưu trữ $myfielddưới dạng trường thứ 4 trong tệp, bất kể khoảng trắng ở giữa chúng.

$ while read -r _ _ _ a _; do echo "4th field: $a"; done < a
4th field: 1
4th field: 2
4th field: 3
4th field: 4

quyến rũ

Điều này bắt ba nhóm không gian và không có không gian với ([^ ]*[ ]*){3}. Sau đó, nó bắt bất cứ thứ gì đến cho đến khi một không gian là trường thứ 4, cuối cùng nó được in \1.

$ sed -r 's/^([^ ]*[ ]*){3}([^ ]*).*/\2/' a
1
2
3
4

2
awkkhông chỉ thanh lịch và đơn giản, nó còn được bao gồm trong VMware ESXi, nơi trcòn thiếu.
121391

2
@ user121391 còn một lý do khác để sử dụng awk!
fedorqui 'SO ngừng làm hại'

@fedorqui Tôi chưa bao giờ nghe thấy dấu gạch dưới là "biến rác". Bạn có thể cung cấp thêm cái nhìn sâu sắc / tài liệu tham khảo về điều này?
BryKKan

1
@BryKKan Tôi đã tìm hiểu về nó trong Greg. Làm cách nào tôi có thể đọc một tệp (luồng dữ liệu, biến) theo từng dòng (và / hoặc từng trường)? : Một số người sử dụng biến throwaway _ làm "biến rác" để bỏ qua các trường. Nó (hoặc thực sự là bất kỳ biến nào) cũng có thể được sử dụng nhiều lần trong một readlệnh, nếu chúng ta không quan tâm đến những gì đi vào nó . Nó có thể là bất cứ điều gì, chỉ là nó bằng cách nào đó đã trở thành tiêu chuẩn thay vì junk_varhoặc whatever:)
fedorqui 'SO ngừng gây hại'

25

giải pháp ngắn nhất / thân thiện nhất

Sau khi trở nên thất vọng với quá nhiều hạn chế cut, tôi đã viết bài thay thế của riêng mình, mà tôi đã kêu gọi cuts"cắt giảm steroid".

cắt giảm cung cấp những gì có thể là giải pháp tối giản nhất cho vấn đề này và nhiều vấn đề cắt / dán liên quan khác .

Một ví dụ, trong số rất nhiều, giải quyết câu hỏi đặc biệt này:

$ cat text.txt
0   1        2 3
0 1          2   3 4

$ cuts 2 text.txt
2
2

cuts hỗ trợ:

  • tự động phát hiện hầu hết các dấu phân cách trường phổ biến trong các tệp (+ khả năng ghi đè mặc định)
  • đa char, hỗn hợp char và regex phù hợp với dấu phân cách
  • trích xuất các cột từ nhiều tệp với các dấu phân cách hỗn hợp
  • bù đắp từ cuối dòng (sử dụng số âm) ngoài đầu dòng
  • tự động dán cạnh cột (không cần phải gọi pasteriêng)
  • hỗ trợ sắp xếp lại lĩnh vực
  • một tập tin cấu hình nơi người dùng có thể thay đổi sở thích cá nhân của họ
  • nhấn mạnh lớn vào sự thân thiện với người dùng và yêu cầu gõ tối giản

và nhiều hơn nữa. Không ai trong số đó được cung cấp theo tiêu chuẩn cut.

Xem thêm: https://stackoverflow.com/a/24543231/1296044

Nguồn và tài liệu (phần mềm miễn phí): http://arielf.github.io/ype/


4

Perl one-liner này cho thấy Perl có liên quan chặt chẽ đến awk như thế nào:

perl -lane 'print $F[3]' text.txt

Tuy nhiên, @Fmảng autosplit bắt đầu tại chỉ mục $F[0]trong khi các trường awk bắt đầu bằng$1


3

Với các phiên bản cuttôi biết, không, điều này là không thể. cutchủ yếu hữu ích cho việc phân tích cú pháp các tệp trong đó dấu phân cách không phải là khoảng trắng (ví dụ /etc/passwd) và có một số trường cố định. Hai dấu phân cách trong một hàng có nghĩa là một trường trống và điều đó cũng đúng với khoảng trắng.

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.