Làm thế nào để grep hàng có giá trị nhất định trong một cột cụ thể?


9

Tôi có một tập tin như sau

  200.000    1.353    0.086
  200.250    1.417    0.000
  200.500    1.359    0.091
  200.750    1.423    0.000
  201.000    1.365    0.093
  201.250    1.427    0.000
  201.500    1.373    0.093
  201.750    1.432    0.000
  202.000    1.383    0.091
  202.250    1.435    0.000
  202.500    1.392    0.087
  202.750    1.436    0.000
  203.000    1.402    0.081
  203.250    1.437    0.001
  203.500    1.412    0.073
  204.000    1.423    0.065
  204.500    1.432    0.055
  205.000    1.441    0.045  

Tôi chỉ muốn grep các hàng có trong cột đầu tiên là số thập phân .000 và .500 để đầu ra sẽ như thế này

  200.000    1.353    0.086
  200.500    1.359    0.091
  201.000    1.365    0.093
  201.500    1.373    0.093
  202.000    1.383    0.091
  202.500    1.392    0.087
  203.000    1.402    0.081
  203.500    1.412    0.073
  204.000    1.423    0.065
  204.500    1.432    0.055
  205.000    1.441    0.045  

2
Có vẻ đủ dễ dàng. Bạn đã thử những gì cho đến nay? Mã của bạn có vấn đề gì?
John1024

có thể nó dễ với bạn nhưng tôi đã thử với grep '.000' | grep '.005' nhưng nó cũng sắp xếp các hàng có cùng giá trị trong các cột khác
Mohsen El-Tahawy

3
Rất tốt. Mọi người ở đây sẽ thông cảm hơn nhiều nếu bạn thể hiện một nỗ lực trung thực để tự giải quyết vấn đề. Các mã trong bình luận của bạn cho thấy rằng. Trong tương lai, nếu bạn bao gồm những nỗ lực như thế trong câu hỏi của mình, bạn có thể sẽ nhận được phản hồi tốt hơn nhanh hơn.
John1024

Câu trả lời:


14

Bạn không sử dụng grep. Sử dụng awk.

"your data" | awk '$1 ~ /\.[05]00/'

Rất tốt. Như được viết, mã phụ thuộc vào việc có chính xác ba chữ số sau số thập phân. Nó sẽ mạnh mẽ hơn để sử dụng awk '$1 ~ /\.[05]0*$/'.
John1024

1
@ John1024, thực sự như đã viết mã phụ thuộc vào việc có ít nhất ba chữ số sau số thập phân. Tôi sẽ nghiêng về phía awk '$1 ~ /\.[05]00$/'mình (yêu cầu chính xác ba chữ số), trừ khi tôi có lý do để nghĩ rằng các vị trí thập phân thay đổi được mong đợi trong đầu vào.
tự đại diện

2
@Wildcard Nếu có nhiều hơn ba, mã có thể thất bại. Ví dụ : echo 0.5001 | awk '$1 ~ /\.[05]00/'. Nó chỉ hoạt động đáng tin cậy nếu có chính xác ba.
John1024

4
awk '$1 ~ /\.[50]00/ { print $0 }' myFile.txt

Cột đầu tiên $1sẽ được khớp với /\.500|\.000/các dấu chấm được thoát thành các chấm theo nghĩa đen chứ không phải biểu thức bất kỳ ký tự nào ~là khớp một phần và in toàn bộ dòng$0


2
Không có lý do để bao gồm { print $0 }; đó là hành động mặc định của Awk.
tự đại diện

4

Tôi chỉ muốn grep các hàng có trong cột đầu tiên là thập phân .000 và .500

Ý nghĩ đầu tiên của tôi

grep '^ *[0-9][0-9][0-9]\.[50]00' filename

Kiểm tra nhanh bằng WSL

$ head testdata
              200.000    1.353    0.086
              200.250    1.417    0.000
              200.500    1.359    0.091
              200.750    1.423    0.000
              201.000    1.365    0.093
              201.250    1.427    0.000
              201.500    1.373    0.093
              201.750    1.432    0.000
              202.000    1.383    0.091
              202.250    1.435    0.000
$ grep '^ *[0-9][0-9][0-9]\.[50]00' testdata
              200.000    1.353    0.086
              200.500    1.359    0.091
              201.000    1.365    0.093
              201.500    1.373    0.093
              202.000    1.383    0.091
              202.500    1.392    0.087
              203.000    1.402    0.081
              203.500    1.412    0.073
              204.000    1.423    0.065
              204.500    1.432    0.055
              205.000    1.441    0.045

Có nhiều cách ngắn gọn hơn để thể hiện điều này.

$ grep -E '^ *[0-9]{3}\.[50]00' testdata
              200.000    1.353    0.086
              200.500    1.359    0.091
              201.000    1.365    0.093
              201.500    1.373    0.093
              202.000    1.383    0.091
              202.500    1.392    0.087
              203.000    1.402    0.081
              203.500    1.412    0.073
              204.000    1.423    0.065
              204.500    1.432    0.055
              205.000    1.441    0.045

Nếu cột đầu tiên có thể có phần nguyên 3 chữ số

grep -E '^ *[0-9]+\.[05]00' testdata

Trong một số trường hợp, bạn có thể cần phải sử dụng [:digit:]thay thế [0-9].

Và như thế.

man grep là bạn của bạn.


Cách sử dụng grepnày dễ sử dụng hơn của tôi. Tôi sẽ không đăng một câu trả lời nếu tôi đã thấy điều này đầu tiên. Công việc tốt!
Yokai

2

Tùy thuộc vào trường hợp sử dụng của bạn, bạn cũng có thể sử dụng các thao tác số thực tế:

$ awk '{a = $1 % 1} a == 0 || a == 0.5' /tmp/foo
  200.000    1.353    0.086
  200.500    1.359    0.091
  201.000    1.365    0.093
  201.500    1.373    0.093
  202.000    1.383    0.091
  202.500    1.392    0.087
  203.000    1.402    0.081
  203.500    1.412    0.073
  204.000    1.423    0.065
  204.500    1.432    0.055
  205.000    1.441    0.045

Đã thử nghiệm với BSD awk (OSX El Capitan, 20070501) và GNU awk 4.1.4.


1
Cảnh báo: kiểm tra tính bằng nhau chính xác của dấu phẩy động (mà awk sử dụng) thường cho kết quả 'sai' trừ khi các giá trị không có phần phân số (và không quá lớn về độ lớn) hoặc phần phân đoạn là 'nhị phân' (chính xác là một nửa, một quý, v.v.) đúng với dữ liệu trong Q này nhưng không có nhiều dữ liệu khác có vẻ giống với dữ liệu không được đề xuất.
dave_thndry_085

1
@ dave_thndry_085 thực sự, nhưng với gawk bạn có thể sử dụng số học chính xác tùy ý , phải thừa nhận rằng tôi không sử dụng chúng ở đây.
muru


2

Với awk:

$>awk '$1%.5==0' data.tsv 
200.000 1.353   0.086
200.500 1.359   0.091
201.000 1.365   0.093
201.500 1.373   0.093
202.000 1.383   0.091
202.500 1.392   0.087
203.000 1.402   0.081
203.500 1.412   0.073
204.000 1.423   0.065
204.500 1.432   0.055
205.000 1.441   0.045

Với mlr:

$>mlr --ifs tab --onidx filter '$1%.5==0' data.tsv 
200.000 1.353 0.086
200.500 1.359 0.091
201.000 1.365 0.093
201.500 1.373 0.093
202.000 1.383 0.091
202.500 1.392 0.087
203.000 1.402 0.081
203.500 1.412 0.073
204.000 1.423 0.065
204.500 1.432 0.055
205.000 1.441 0.045

2

Ok, hơi muộn khi thêm vào đóng góp của tôi, nhưng tôi nghĩ nó đáng giá.

Yêu cầu phải đáp ứng, theo OP là cột đầu tiên có giá trị thập phân bằng .000hoặc .500duy nhất. Không có quy định nào về giá trị hàng đầu, theo phạm vi hoặc độ dài. Để mạnh mẽ, không nên giả sử bị ràng buộc bởi bất cứ điều gì ngoại trừ việc không có các ký tự không trống trước cột đầu tiên (hoặc không còn là cột đầu tiên) và nội dung của cột đầu tiên sẽ có dấu thập phân ., trong đó ở đâu đó

OP đang muốn sử dụng grep, nó sẽ in toàn bộ dòng khi tìm thấy kết quả khớp, do đó, điều duy nhất cần làm là tạo mẫu phù hợp với tất cảchỉ những gì được yêu cầu.

Đơn giản, và không có lý do để sử dụng sedhoặc awknhư `grep có thể xử lý nguồn dưới dạng tệp hoặc đường ống.

Để grepsử dụng tập tingrep '^[^.]*\.[05]0\{2\}\s' the_file.txt

Để greptừ một đường ống, sử dụngmy_command | grep '^[^.]*\.[05]0\{2\}\s'

Mẫu là : ^, bắt đầu ở đầu dòng; [^.], phù hợp với bất kỳ ký tự không thập phân; *, càng nhiều lần càng tốt (bao gồm cả không); \., khớp một dấu thập phân; [05], khớp với năm hoặc không; 0\{2\}, khớp 2 số không nữa (dấu gạch chéo ngược trước dấu ngoặc mở và đóng ngăn vỏ cố gắng thực hiện mở rộng dấu ngoặc); \s, khớp với một ký tự khoảng trắng (có nghĩa là phần cuối của cột - để sử dụng trong trường hợp sử dụng khác, thay thế bằng dấu tách cột, thường là dấu phẩy, dấu chấm phẩy hoặc tab \t).

Lưu ý rằng điều này sẽ khớp chính xác với những gì OP yêu cầu. Nó sẽ không khớp .5000hoặc .0000thậm chí tương đương về số, bởi vì mẫu tìm kiếm năm hoặc một số không, theo sau là chính xác hơn 2 số 0 theo sau là khoảng trắng. Nếu điều đó có ý nghĩa, thì tất cả các câu trả lời khác, cho đến nay, đều thất bại ở chỗ chúng sẽ khớp với bất kỳ số 0 nào, lớn hơn 1, sau chữ số kiểm tra. Và ngoại trừ câu trả lời của FloHimelf, họ sẽ khớp bất cứ thứ gì trong cột thứ hai bắt đầu .000 hoặc .500, bao gồm .0003.500T, và bởi FloHimelf sẽ khớp với bất cứ thứ gì tương đương về mặt toán học .0.5, cho dù có bao nhiêu số không. Cái cuối cùng, trong khi không khớp với những gì OP đã nêu có khả năng khớp với những gì OP cần.

Cuối cùng, nếu sức mạnh và tốc độ của awkmong muốn, mặc dù OP đã yêu cầu grep, thì lệnh sẽ là:

Với một tập tin awk '$1 ~ /[^.]\.[05]0{2}$/' the_file.txt

Với một đường ống my_command | awk '$1 ~ /[^.]\.[05]0{2}$/'


1

Nếu bạn khăng khăng sử dụng grep, thì điều này có thể phù hợp với bạn. Tôi đã lưu đầu ra đầu tiên bạn cung cấp cho một tệp văn bản có tên là "file.txt" và sau đó sử dụng lệnh sau:

grep -e '2[^ ]*.000' file.txt & grep -e '2[^ ]*.500' file.txt

Cung cấp một đầu ra của:

200.000    1.353    0.086
200.500    1.359    0.091
201.500    1.373    0.093
201.000    1.365    0.093
202.500    1.392    0.087
202.000    1.383    0.091
203.500    1.412    0.073
203.000    1.402    0.081
204.500    1.432    0.055
204.000    1.423    0.065
205.000    1.441    0.045

Bạn sẽ không phải lưu đầu ra vào một tệp văn bản nếu nó đã có trong một tệp. Nhưng trong trường hợp nó không được lưu vào một tệp, bạn cũng có thể chuyển dữ liệu vào lệnh grep tôi đã cung cấp và nó sẽ hoạt động ít nhất cho đến khi số đầu tiên 2, trong cột đầu tiên không còn là a 2. Tại thời điểm đó, bạn sẽ cần cập nhật lệnh grep với ký tự phù hợp để in chính xác.

Điều đang xảy ra với greplệnh kép này là lệnh đầu tiên grepđược gửi đến nền với &toán tử. Khi nó được gửi đến nền, greplệnh tiếp theo sẽ thực thi ngay sau đó cung cấp cho bạn một đầu ra thống nhất. Đối với nhiệm vụ bạn cần hoàn thành để được thực hiện dễ dàng hơn, bạn nên làm theo ví dụ mà người khác đã đưa ra và sử dụng awkhoặc thậm chí sed.

(biên tập)

Đây không phải là cách sử dụng grep tốt nhất hoặc hiệu quả nhất cho nhu cầu của bạn nhưng nó đủ để bạn chơi xung quanh một chút và cảm nhận tốt hơn về grep.


Quá trình đầu tiên không chạy trong nền, nhưng không được trình bày trong đó bao gồm chạy trong nền nhưng khá hơn một chút. Và rất khó có thể tạo ra đầu ra theo thứ tự giống như đầu vào; ngay cả trong ví dụ khá nhỏ của bạn, nó đã bị sai ở dòng thứ ba.
dave_thndry_085

Ông không đề cập rằng đầu ra cần phải theo một thứ tự cụ thể. Chỉ có điều nó cần phải cụ thể cho .500.000của cột đầu tiên. Nếu nó cần theo một thứ tự cụ thể, từ ít nhất đến lớn nhất, điều đó có thể dễ dàng được thực hiện. Tuy nhiên, 3 chữ số đầu tiên của các cột đầu tiên được in theo thứ tự ít nhất là lớn nhất. Đó là kết quả của 2[^ ]*.0002[^ ]*.500. Nó khá phù hợp với những gì OP yêu cầu.
Yokai

Cũng lưu ý chỉnh sửa của tôi để từ chối hiệu quả cho lệnh tôi đã cung cấp.
Yokai
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.