Tôi cần xác định tư thế của một ký tự trong chuỗi bằng lệnh grep.
Ví dụ, chuỗi là RAMSITALSKHMAN|1223333
.
grep -n '[^a-zA-Z0-9\$\~\%\#\^]'
Làm thế nào để tôi tìm vị trí của |
chuỗi đã cho?
Tôi cần xác định tư thế của một ký tự trong chuỗi bằng lệnh grep.
Ví dụ, chuỗi là RAMSITALSKHMAN|1223333
.
grep -n '[^a-zA-Z0-9\$\~\%\#\^]'
Làm thế nào để tôi tìm vị trí của |
chuỗi đã cho?
Câu trả lời:
Bạn có thể sử dụng -b
để lấy phần bù byte, giống như vị trí cho văn bản đơn giản (nhưng không phải cho UTF-8 hoặc tương tự).
$ echo "RAMSITALSKHMAN|1223333" | grep -aob '|'
14:|
Ở trên, tôi sử dụng công -a
tắc để báo cho grep sử dụng đầu vào dưới dạng văn bản; cần thiết khi hoạt động trên các tệp nhị phân và -o
chuyển sang chỉ xuất (các) ký tự phù hợp.
Nếu bạn chỉ muốn vị trí, bạn có thể sử dụng grep để chỉ trích xuất vị trí:
$ echo "RAMSITALSKHMAN|1223333" | grep -aob '|' | grep -oE '[0-9]+'
14
Nếu bạn nhận được đầu ra lạ, hãy kiểm tra xem grep có bật màu không. Bạn có thể vô hiệu hóa màu sắc bằng cách chuyển --colors=never
đến grep hoặc bằng cách thêm tiền tố vào lệnh grep bằng một \
(sẽ vô hiệu hóa bất kỳ bí danh nào), ví dụ:
$ echo "RAMSITALSKHMAN|1223333" | grep -aob '|' --color=never | \grep -oE '^[0-9]+'
14
Đối với một chuỗi trả về nhiều kết quả khớp, hãy nối qua head -n1
để có được kết quả khớp đầu tiên.
Lưu ý rằng tôi sử dụng cả hai ở trên và lưu ý rằng cái sau sẽ không hoạt động nếu grep bị "bí danh" thông qua một tệp thực thi (tập lệnh hoặc cách khác), chỉ khi sử dụng bí danh.
2
;)
^
:)
0:|
làm đầu ra-- bởi vì 0 là vị trí byte của đầu dòng |
được tìm thấy.
grep (GNU grep) 2.27
. Có lẽ bạn đang sử dụng OS X?
Thử:
printf '%s\n' 'RAMSITALSKHMAN|1223333.' | grep -o . | grep -n '|'
đầu ra:
15:|
Điều này sẽ cung cấp cho bạn vị trí với chỉ số dựa trên 1.
printf '%s\n' '|' | grep -o . | grep -n '|'
in 1
, không 0
như mong đợi.
Nếu bạn đang sử dụng bash shell, bạn có thể sử dụng các hoạt động được tích hợp hoàn toàn mà không cần phải sinh ra các quy trình bên ngoài như grep hoặc awk :
$ str="RAMSITALSKHMAN|1223333"
$ tmp="${str%%|*}"
$ if [ "$tmp" != "$str" ]; then
> echo ${#tmp}
> fi
14
$
Điều này sử dụng một mở rộng tham số để loại bỏ tất cả các lần xuất hiện |
theo sau bởi bất kỳ chuỗi nào và lưu nó trong một biến tạm thời. Sau đó, chỉ là vấn đề đo chiều dài của biến tạm thời để lấy chỉ số của |
.
Lưu ý if
là kiểm tra xem |
có tồn tại trong chuỗi gốc không. Nếu không, biến tạm thời sẽ giống như biến ban đầu.
Cũng lưu ý rằng điều này cung cấp chỉ mục dựa trên zero |
, thường hữu ích khi lập chỉ mục chuỗi bash. Tuy nhiên, nếu bạn yêu cầu chỉ mục một, thì bạn có thể làm điều này:
$ echo $((${#tmp}+1))
15
$
Bạn có thể sử dụng index
chức năng của awk để trả về vị trí trong các ký tự nơi xảy ra trận đấu:
echo "RAMSITALSKHMAN|1223333"|awk 'END{print index($0,"|")}'
15
Nếu bạn không phiền khi sử dụng index
chức năng của Perl , điều này sẽ xử lý báo cáo bằng không, một hoặc nhiều lần xuất hiện của một ký tự:
echo "|abc|xyz|123456|zzz|" | \
perl -nle '$pos=-1;while (($off=index($_,"|",$pos))>=0) {print $off;$pos=$off+1}'
Để dễ đọc, chỉ, đường ống đã được chia thành hai dòng.
Miễn là tìm thấy ký tự đích, index
trả về giá trị dương dựa trên 0 (0). Do đó, chuỗi "abc | xyz | 123456 | zzz |" khi phân tích cú pháp trả về các vị trí 0, 4, 8, 15 và 19.
RAMSITALSKHMAN|1|223333
Chúng tôi cũng có thể làm điều đó bằng cách sử dụng "expr match" hoặc "expr index"
expr khớp với chuỗi $ $ chuỗi con trong đó chuỗi con $ là RE.
echo `expr match "RAMSITALSKHMAN|1223333" '[A-Z]*.|'`
Và ở trên sẽ cung cấp cho bạn vị trí vì nó trả về độ dài của chuỗi con phù hợp.
Nhưng để cụ thể hơn cho chỉ mục tìm kiếm:
mystring="RAMSITALSKHMAN|122333"
echo `expr index "$mystring" '|'`
awk
giải pháp có thể được sửa đổi một cách tầm thường để báo cáo thông tin này trên mỗi dòng của tệp (tất cả những gì bạn phải làm là loại bỏ END
, điều không bao giờ thực sự cần thiết, từ câu trả lời của JRFerguson và Avinash Raj đã làm điều đó rồi) ; trong khi đó, để làm điều đó với expr
giải pháp, bạn sẽ cần thêm một vòng lặp rõ ràng (và câu trả lời của Gnouc không dễ thích nghi để làm điều đó, tôi có thể thấy) và (2) các awk
giải pháp có thể được điều chỉnh để báo cáo tất cả phù hợp với từng dòng dễ dàng hơn so với expr
giải pháp (trên thực tế, Avinash Raj cũng đã làm điều đó).
echo `...`
ở đây?
$ echo 'RAMSITALSKHMAN|1223333'| awk 'BEGIN{ FS = "" }{for(i=1;i<=NF;i++){if($i=="|"){print i;}}}'
15
Bằng cách đặt dấu phân cách Trường thành chuỗi rỗng, awk biến ký tự riêng lẻ trong bản ghi thành các trường riêng biệt.
một số lựa chọn thay thế bao gồm:
tương tự như câu trả lời của Gnouc, nhưng với vỏ:
echo 'RAMSITALSKHMAN|1223333' |
tr -c \| \\n |
sh
sh: line 15: syntax error near unexpected token `|
sh: line 15: `|'
với sed
và dc
có thể kéo dài nhiều dòng:
echo 'RAMSITALSKHMAN|1223333' |
sed 's/[^|]/1+/g;s/|/p/;1i0 1+' |dc
15
với $IFS
...
IFS=\|; set -f; set -- ${0+RAMSITALSKHMAN|1223333}; echo $((${#1}+1))
Điều đó cũng sẽ cho bạn biết có bao nhiêu giống như ...
echo $(($#-1))