Làm cách nào để tôi grep
tab (\ t) trong các tệp trên nền tảng Unix?
Làm cách nào để tôi grep
tab (\ t) trong các tệp trên nền tảng Unix?
Câu trả lời:
Nếu sử dụng GNU grep, bạn có thể sử dụng biểu thức chính quy theo kiểu Perl:
grep -P '\t' *
-P
lựa chọn.
Bí quyết là sử dụng dấu $ trước dấu ngoặc đơn . Nó cũng hoạt động để cắt và các công cụ khác.
grep $'\t' sample.txt
zsh
tốt, như tôi có thể nói. Bạn có thể nhận xét về ngữ nghĩa của $
dấu hiệu đó là gì?
$'\t'' '
. Một ví dụ thực tế cho thấy nó cũng hoạt động với sh (không chỉ bash, không được cài đặt mặc định trên Android) busybox grep -oE '^nodev'$'\t''fuse$' /proc/filesystems
.
Tôi chưa bao giờ quản lý để làm cho vi khuẩn '\ t' hoạt động với grep. Tuy nhiên tôi tìm thấy hai giải pháp thay thế:
<Ctrl-V> <TAB>
(nhấn Ctrl-V sau đó gõ tab)foo | awk '/\t/'
| awk '/\t/'
giải pháp sẽ làm việc cho tất cả vỏ, nền tảng và hệ thống.
awk
hoạt động tốt ở đây nhưng trong một số thử nghiệm trên máy của tôi với các tệp rất lớn thì chậm hơn khoảng 30% so với sử dụng grep -P
. Điều này có thể là tầm thường và không liên quan dựa trên trường hợp sử dụng, và awk
có thể tốt hơn chỉ đơn giản là cho khả năng đọc và tính di động.
Từ câu trả lời này trên Hỏi Ubuntu:
Yêu cầu grep sử dụng các biểu thức chính quy theo định nghĩa của Perl (Perl có
\t
dưới dạng tab):grep -P "\t" <file name>
Sử dụng ký tự tab theo nghĩa đen:
grep "^V<tab>" <filename>
Sử dụng
printf
để in một ký tự tab cho bạn:grep "$(printf '\t')" <filename>
Một cách là (đây là với Bash)
grep -P '\t'
-P
bật biểu thức chính quy Perl để \ t sẽ hoạt động.
Như người dùng thư giãn nói, nó có thể đặc trưng cho GNU grep. Cách khác là chèn một tab vào đó nếu shell, trình soạn thảo hoặc thiết bị đầu cuối sẽ cho phép nó.
Một cách khác để chèn tab theo nghĩa đen bên trong biểu thức là sử dụng $'\t'
trích dẫn ít được biết đến trong Bash:
grep $'foo\tbar' # matches eg. 'foo<tab>bar'
(Lưu ý rằng nếu bạn khớp với các chuỗi cố định, bạn có thể sử dụng chế độ này với chế độ '-F'.)
Đôi khi sử dụng các biến có thể làm cho ký hiệu dễ đọc và dễ quản lý hơn một chút:
tab=$'\t' # `tab=$(printf '\t')` in POSIX
id='[[:digit:]]\+'
name='[[:alpha:]_][[:alnum:]_-]*'
grep "$name$tab$id" # matches eg. `bob2<tab>323`
Đây không phải là chính xác những gì bạn đang tìm kiếm, nhưng có thể hoạt động trong trường hợp của bạn
grep '[[:blank:]]'
Tương đương với
grep -P '[ \t]'
Vì vậy, nó sẽ tìm thấy Space và Tab.
Lưu ý, nó không được quảng cáo trong tôi man grep
, nhưng vẫn hoạt động
$ man grep | grep trống | wc 0 0 0
-P
đối số đã được thêm vào.
Về cơ bản có hai cách để giải quyết nó:
( Khuyến nghị ) Sử dụng cú pháp biểu thức chính quy được hỗ trợ bởi grep (1). Modern grep (1) hỗ trợ hai dạng cú pháp regex POSIX 1003.2: REs cơ bản (lỗi thời) và REs hiện đại . Cú pháp được mô tả chi tiết trên các trang man re_format (7) và regex (7) là một phần của hệ thống BSD và Linux tương ứng. GNU grep (1) cũng hỗ trợ RE tương thích với Perl do thư viện pcre (3) cung cấp.
Trong ngôn ngữ regex, biểu tượng tab thường được mã hóa bởi \t
nguyên tử. Nguyên tử được hỗ trợ bởi các biểu thức chính quy mở rộng BSD ( egrep
, grep -E
trên hệ thống tương thích BSD), cũng như REs tương thích Perl ( pcregrep
, GNU grep -P
).
Cả hai biểu thức chính quy cơ bản và REs mở rộng của Linux dường như không hỗ trợ cho \t
. Vui lòng tham khảo trang hướng dẫn tiện ích UNIX để biết ngôn ngữ regex nào hỗ trợ (do đó có sự khác biệt giữa sed (1), awk (1) và pcregrep (1) biểu thức chính quy).
Do đó, trên Linux:
$ grep -P '\t' FILE ...
Trên hệ thống BSD như nhau:
$ egrep '\t' FILE ...
$ grep -E '\t' FILE ...
Truyền ký tự tab thành mẫu. Điều này rất đơn giản khi bạn chỉnh sửa tệp tập lệnh:
# no tabs for Python please!
grep -q ' ' *.py && exit 1
Tuy nhiên, khi làm việc trong trình bao tương tác, bạn có thể cần phải dựa vào khả năng của trình bao và thiết bị đầu cuối để nhập ký hiệu phù hợp vào dòng. Trên hầu hết các thiết bị đầu cuối, điều này có thể được thực hiện thông qua tổ hợp phím Ctrl
+ V
hướng dẫn thiết bị đầu cuối xử lý ký tự đầu vào tiếp theo theo nghĩa đen (nghĩa V
là "nguyên văn"):
$ grep '<Ctrl>+<V><TAB>' FILE ...
Một số shell có thể cung cấp hỗ trợ nâng cao cho việc sắp chữ lệnh. Chẳng hạn, trong bash (1) các từ có dạng $'string'
được xử lý đặc biệt:
bash$ grep $'\t' FILE ...
Mặc dù vậy, xin lưu ý, trong khi tốt trong một dòng lệnh, điều này có thể tạo ra các vấn đề tương thích khi tập lệnh sẽ được chuyển sang nền tảng khác. Ngoài ra, hãy cẩn thận với dấu ngoặc kép khi sử dụng sản phẩm đặc biệt, vui lòng tham khảo bash (1) để biết chi tiết.
Đối với shell Bourne (và không chỉ), hành vi tương tự có thể được mô phỏng bằng cách sử dụng thay thế lệnh được tăng cường bởi printf (1) để xây dựng regex thích hợp:
$ grep "`printf '\t'`" FILE ...
sử dụng gawk, đặt dấu phân cách trường thành tab (\ t) và kiểm tra số lượng trường. Nếu có nhiều hơn 1, thì có / là các tab
awk -F"\t" 'NF>1' file
awk /\t/
là đủ cho câu hỏi của op.
Một lựa chọn tốt là sử dụng 'sed as grep' (như được giải thích trong hướng dẫn sed cổ điển này ).
sed -n 's/pattern/&/p' file
Ví dụ (hoạt động trong bash, sh, ksh, csh, ..):
[~]$ cat testfile
12 3
1 4 abc
xa c
a c\2
1 23
[~]$ sed -n 's/\t/&/p' testfile
xa c
a c\2
[~]$ sed -n 's/\ta\t/&/p' testfile
a c\2
Cách +1, hoạt động trong ksh, dash, v.v .: sử dụng printf để chèn TAB:
grep "$(printf 'BEGIN\tEND')" testfile.txt
grep "$(printf '\t')" testfile.txt
Sử dụng phương pháp 'sed-as-grep', nhưng thay thế các tab bằng ký tự hiển thị của sở thích cá nhân là phương pháp ưa thích của tôi, vì nó hiển thị rõ ràng cả tệp nào chứa thông tin được yêu cầu và cũng được đặt trong dòng:
sed -n 's/\t/\*\*\*\*/g' file_name
Nếu bạn muốn sử dụng thông tin dòng / tệp hoặc các tùy chọn grep khác, nhưng cũng muốn xem thay thế hiển thị cho ký tự tab, bạn có thể đạt được điều này bằng cách
grep -[options] -P '\t' file_name | sed 's/\t/\*\*\*\*/g'
Ví dụ:
$ echo "A\tB\nfoo\tbar" > test
$ grep -inH -P '\t' test | sed 's/\t/\*\*\*\*/g'
test:1:A****B
test:2:foo****bar
EDIT: Rõ ràng ở trên chỉ hữu ích cho việc xem nội dung tệp để định vị các tab --- nếu mục tiêu là xử lý các tab như một phần của phiên kịch bản lớn hơn, điều này không phục vụ bất kỳ mục đích hữu ích nào.
Bạn có thể muốn sử dụng grep "$(echo -e '\t')"
Chỉ yêu cầu là echo
có khả năng giải thích các dấu gạch chéo ngược.
Những phương pháp nhận dạng nhị phân thay thế là hoàn toàn chức năng. Và, tôi thực sự thích một người sử dụng awk, vì tôi không thể nhớ được cách sử dụng cú pháp với các ký tự nhị phân đơn. Tuy nhiên, cũng có thể gán một biến shell một giá trị theo kiểu di động POSIX (tức là TAB = echo "@" | tr "\100" "\011"
), và sau đó sử dụng nó từ mọi nơi, theo kiểu di động POSIX; cũng như (tên tệp grep "$ TAB"). Mặc dù giải pháp này hoạt động tốt với TAB, nhưng nó cũng sẽ hoạt động tốt với các ký tự nhị phân khác, khi một giá trị nhị phân mong muốn khác được sử dụng trong phép gán (thay vì giá trị cho ký tự TAB thành 'tr').
Ký hiệu $ '\ t' được đưa ra trong các câu trả lời khác là đặc trưng cho vỏ - nó dường như hoạt động trong bash và zsh nhưng không phổ biến.
LƯU Ý: Dưới đây là dành cho fish
shell và không hoạt động trong bash :
Trong fish
shell, người ta có thể sử dụng một trích dẫn \t
, ví dụ:
grep \t foo.txt
Hoặc người ta có thể sử dụng các ký hiệu hex hoặc unicode, ví dụ:
grep \X09 foo.txt
grep \U0009 foo.txt
(những ký hiệu này hữu ích cho các ký tự bí truyền hơn)
Vì các giá trị này phải được bỏ trích dẫn, người ta có thể kết hợp các giá trị được trích dẫn và không trích dẫn bằng cách ghép:
grep "foo"\t"bar"
Bạn có thể gõ
grep \ t foo
grep '\ t' foo
để tìm kiếm ký tự tab trong tệp foo. Bạn có thể cũng có thể thực hiện các mã thoát khác, mặc dù tôi chỉ thử nghiệm \ n. Mặc dù việc này khá tốn thời gian và không rõ lý do tại sao bạn muốn, trong zsh, bạn cũng có thể nhập ký tự tab, quay lại từ đầu, grep và kèm theo tab với dấu ngoặc kép.
Tìm khoảng trống nhiều lần [[: dấu cách:]] *
grep [[: dấu cách:]] * '.' '.'
Sẽ tìm thấy một cái gì đó như thế này:
'tab' ..
Đây là những trích dẫn đơn (') và không gấp đôi (").
Đây là cách bạn thực hiện ghép trong grep. = -)
grep "<Ctrl+V><TAB>"
, nó hoạt động (nếu lần đầu tiên: gõgrep "
rồi nhấn tổ hợp phím Ctrl + V, sau đó nhấn phím TAB, sau đó nhập"
và nhấn enter, voilà!)