Truy cập x ký tự cuối cùng của một chuỗi trong Bash


125

Tôi phát hiện ra rằng với ${string:0:3}một người có thể truy cập 3 ký tự đầu tiên của một chuỗi. Có phương pháp tương đương dễ dàng để truy cập ba ký tự cuối cùng không?

Câu trả lời:


236

Ba ký tự cuối cùng của string:

${string: -3}

hoặc là

${string:(-3)}

(nhớ khoảng trống giữa :-3ở dạng đầu tiên).

Vui lòng tham khảo Mở rộng Thông số Vỏ trong sách hướng dẫn tham khảo :

${parameter:offset}
${parameter:offset:length}

Expands to up to length characters of parameter starting at the character
specified by offset. If length is omitted, expands to the substring of parameter
starting at the character specified by offset. length and offset are arithmetic
expressions (see Shell Arithmetic). This is referred to as Substring Expansion.

If offset evaluates to a number less than zero, the value is used as an offset
from the end of the value of parameter. If length evaluates to a number less than
zero, and parameter is not ‘@’ and not an indexed or associative array, it is
interpreted as an offset from the end of the value of parameter rather than a
number of characters, and the expansion is the characters between the two
offsets. If parameter is ‘@’, the result is length positional parameters
beginning at offset. If parameter is an indexed array name subscripted by ‘@’ or
‘*’, the result is the length members of the array beginning with
${parameter[offset]}. A negative offset is taken relative to one greater than the
maximum index of the specified array. Substring expansion applied to an
associative array produces undefined results.

Note that a negative offset must be separated from the colon by at least one
space to avoid being confused with the ‘:-’ expansion. Substring indexing is
zero-based unless the positional parameters are used, in which case the indexing
starts at 1 by default. If offset is 0, and the positional parameters are used,
$@ is prefixed to the list.

Vì câu trả lời này nhận được một vài lượt xem thường xuyên, hãy để tôi thêm một khả năng để giải quyết bình luận của John Rix ; như anh ấy đề cập, nếu chuỗi của bạn có độ dài nhỏ hơn 3, ${string: -3}sẽ mở rộng thành chuỗi trống. Trong trường hợp này, nếu bạn muốn mở rộng string, bạn có thể sử dụng:

${string:${#string}<3?0:-3}

Điều này sử dụng ?:toán tử if bậc ba, có thể được sử dụng trong Shell Arithmetic ; vì như đã được tài liệu, offset là một biểu thức số học, điều này là hợp lệ.


5
Lưu ý rằng điều này không hiệu quả nếu chuỗi của bạn ngắn hơn độ lệch âm mà bạn cung cấp. Bạn chỉ nhận được một chuỗi trống trong các trường hợp như vậy.
John Rix

2
@gniourf_gniourf Làm cách nào để sử dụng điều này cùng với thay thế lệnh? Tôi đang cố gắng để trích xuất các ba nhân vật cuối cùng của tên máy của tôi deppfx@localhost:/tmp$ echo ${$(hostname): -3} -bash: ${$(hostname): -3}: bad substitution
deppfx

3
@deppfx: bạn không thể sử dụng Bash. Sử dụng một biến tạm thời: temp=$(hostname); echo "${temp: -3}". Bash cũng có HOSTNAMEbiến (có thể khác hoặc không với đầu ra của hostname). Nếu bạn muốn sử dụng nó, chỉ cần làm echo "${HOSTNAME: -3}".
gniourf_gniourf

Làm thế nào bạn có thể sử dụng điều này từ đầu ra của một đường ống? Ví dụ, some func | echo ${string: -3}- làm cách nào để gán kết quả đầu ra some funccho string?
Michael Hays

1
@MichaelHays: Chỉ cần gán đầu ra của hàm của bạn: string=$(some func)và sau đó echo "${string: -3}".
gniourf_gniourf

48

Bạn có thể sử dụng tail:

$ foo="1234567890"
$ echo -n $foo | tail -c 3
890

Một cách hơi vòng vo để có được ba ký tự cuối cùng là nói:

echo $foo | rev | cut -c1-3 | rev

2
"Đuôi" cũng hữu ích trong dấu gạch ngang, khi không có bash. Ví dụ: phần kịch bản mới nổi.
vskubriev

13

Một giải pháp khác là sử dụng grep -ovới một chút ma thuật regex để có ba ký tự theo sau là cuối dòng:

$ foo=1234567890
$ echo $foo | grep -o ...$
890

Để làm cho nó tùy chọn lấy từ 1 đến 3 ký tự cuối cùng, trong trường hợp chuỗi có ít hơn 3 ký tự, bạn có thể sử dụng egrepvới regex này:

$ echo a | egrep -o '.{1,3}$'
a
$ echo ab | egrep -o '.{1,3}$'
ab
$ echo abc | egrep -o '.{1,3}$'
abc
$ echo abcd | egrep -o '.{1,3}$'
bcd

Bạn cũng có thể sử dụng các phạm vi khác nhau, chẳng hạn như 5,10để lấy năm đến mười ký tự cuối cùng.


7

Để khái quát câu hỏi và câu trả lời của gniourf_gniourf (vì đây là những gì tôi đang tìm kiếm), nếu bạn muốn cắt một loạt các ký tự từ thứ 7 từ cuối đến thứ 3 từ cuối, bạn có thể sử dụng cú pháp này:

${string: -7:4}

Trong đó 4 là độ dài của khóa học (7-3).

Ngoài ra, trong khi giải pháp của gniourf_gniourf rõ ràng là tốt nhất và gọn gàng nhất, tôi chỉ muốn thêm một giải pháp thay thế bằng cách sử dụng cut :

echo $string | cut -c $((${#string}-2))-$((${#string}))

Điều này dễ đọc hơn nếu bạn thực hiện nó thành hai dòng bằng cách xác định độ dài $ {# string} là một biến riêng biệt.


một biến thể không được đề cập trong câu trả lời khác là kết hợp cutcách tiếp cận này để tính điểm bắt đầu / dừng trước và sau đó chỉ sử dụng các biến này trong phần mở rộng tham số (cũng đáng nói rằng cutvà hiệu số bash bắt đầu từ 1 và 0, vì vậy điều này sẽ cần để được tính vào các tính toán, mà tôi không làm gì ở đây): start=$((${#string}-3)); stop=$((${#string}));và sau đó echo ${string: $start : $stop}vsecho $string | cut -c "$start"-"$stop"
michael

(Ồ, đừng bận tâm - tôi thấy rằng nhận xét của tôi không giải quyết được vấn đề chuỗi quá ngắn và sau đó không gây ra kết quả nào - cả phần mở rộng tham số cắt và chuỗi. Tuy nhiên, chia nhỏ thành các biến ( mà không nhất thiết phải gọi ra các lệnh bổ sung) làm cho nó dễ đọc hơn và tôi nghĩ vẫn sẽ là một ý tưởng hay.)
michael
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.