Làm thế nào để có được char ở một vị trí nhất định của một chuỗi trong shell script?


21

Làm thế nào để có được char ở một vị trí nhất định của một chuỗi trong shell script?

Câu trả lời:


35

Trong bash với "Mở rộng tham số" $ {tham số: offset: length}

$ var=abcdef
$ echo ${var:0:1}
a
$ echo ${var:3:1}
d

Chỉnh sửa: Không mở rộng tham số (không thanh lịch lắm, nhưng đó là điều đến với tôi trước)

$ charpos() { pos=$1;shift; echo "$@"|sed 's/^.\{'$pos'\}\(.\).*$/\1/';}
$ charpos 8 what ever here
r



Bạn cũng có thể đặt phần bù 'từ cuối' như vậyecho ${var: -2:1}
Vassilis

Cú pháp đó xuất phát từ ksh93 và cũng được hỗ trợ bởi zshmksh.
Stéphane Chazelas

6

Thay thế cho việc mở rộng tham số là expr substr

substr STRING POS LENGTH
    substring of STRING, POS counted from 1

Ví dụ:

$ expr substr hello 2 1
e

mát mẻ, nên đã kiểm tra expr kỹ hơn.
Forcefsck

1
Mặc dù điều này dường như hoạt động với expr từ GNU coreutils, nhưng substrkhông được bao gồm trong expr từ FreeBSD, NetBSD hoặc OS X. Đây không phải là một giải pháp di động.
ghoti

@ghoti, lưu ý rằng substrban đầu không phải là phần mở rộng GNU. Việc triển khai ban đầu exprđến từ PWB Unix vào cuối những năm 70 và đã có substr(nhưng không :).
Stéphane Chazelas

@ StéphaneChazelas, cảm ơn vì đã thêm quan điểm lịch sử. :) Mặc dù tôi khá chắc chắn rằng việc sử dụng PWB không liên quan đến OP, nhưng thật thú vị khi theo dõi các tính năng và thay đổi qua nhiều thập kỷ. GNU có xu hướng mặc định của nhiều người, nhưng nói chung, tôi nghĩ rằng tôi nên tránh sử dụng các tùy chọn không rõ ràng là POSIX và được biết là bị thiếu trong các đơn vị chính.
ghoti

5

cut -c

Nếu biến không chứa dòng mới, bạn có thể làm:

myvar='abc'
printf '%s\n' "$myvar" | cut -c2

đầu ra:

b

awk substr là một thay thế POSIX khác hoạt động ngay cả khi biến có dòng mới:

myvar="$(printf 'a\nb\n')" # note that the last newline is stripped by
                           # the command substitution
awk -- 'BEGIN {print substr (ARGV[1], 3, 1)}' "$myvar"

đầu ra:

b

printf '%s\n'là để tránh các vấn đề với các ký tự thoát: /programming//a/40423558/895245 ví dụ:

myvar='\n'
printf '%s\n' "$myvar" | cut -c1

đầu ra \như mong đợi.

Xem thêm: /programming/1405611/extracting-first-two-char character-of-a-String-shell-scripting

Đã thử nghiệm trong Ubuntu 19.04.


printf '%s' "$myvar" | cut -c2không phải là POSIX vì đầu ra của printfkhông phải là văn bản trừ khi $myvarkết thúc bằng ký tự dòng mới. Mặt khác, nó giả sử biến không chứa các ký tự dòng mới khi cutcắt từng dòng đầu vào của nó.
Stéphane Chazelas

Người awkta sẽ hiệu quả và đáng tin cậy hơn vớiawk -- 'BEGIN {print substr (ARGV[1], 2, 1)}' "$myvar"
Stéphane Chazelas

Lưu ý rằng với các phiên bản hiện tại của GNU cut, điều đó không hoạt động đối với các ký tự nhiều byte (tương tự với mawk hoặc busybox awk)
Stéphane Chazelas

@ StéphaneChazelas cảm ơn vì những điểm này. Tôi không hiểu ý của bạn trong phần đầu tiên: bạn có nghĩa printf 'abc '| cut -c2là sai vì không \n(điều này tôi không biết), hoặc lệnh sẽ thất bại nếu myvar có dòng mới (điều này tôi đồng ý)?
Ciro Santilli 心 心

1
Hành vi của cutkhông được chỉ định nếu đầu vào không phải là văn bản (mặc dù cutviệc triển khai là bắt buộc để xử lý các dòng hoặc độ dài tùy ý). Đầu ra của printf abckhông phải là văn bản vì nó không kết thúc bằng một ký tự dòng mới. Trên thực tế phụ thuộc vào việc thực hiện, nếu bạn ống đó để cut -c2, bạn nhận được một trong hai b, b<newline>hoặc không có gì cả. Bạn cần printf 'abc\n' | cut -c2có một hành vi được chỉ định bởi POSIX (bắt buộc phải xuất b<newline>)
Stéphane Chazelas

1

Với zshhoặc yash, bạn sẽ sử dụng:

$ text='€$*₭£'
$ printf '%s\n' "${text[3]}"
*

(trong zsh, bạn có thể rút ngắn nó xuống printf '%s\n' $text[3]).


0

Bạn có thể sử dụng lệnh cắt. Để có được tư thế thứ 3:

echo "SAMPLETEXT" | cut -c3

Kiểm tra liên kết này http://www.folkstalk.com/2012/02/cut-command-in-unix-linux-examples.html

( Các trường hợp nâng cao ) Tuy nhiên, sửa đổi IFS cũng là một điều tốt, đặc biệt là khi đầu vào của bạn có thể có khoảng trắng. Trong trường hợp đó, sử dụng một trong những dưới đây

saveifs=$IFS
IFS=$(echo -en "\n\b")
echo "SAMPLETEXT" | cut -c3
IFS=$saveifs

Tôi không thể thấy làm thế nào IFSđể chơi trong mã mà bạn đã đăng.
Kusalananda
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.