Tôi muốn xóa ký tự cuối cùng của chuỗi, tôi đã thử đoạn script nhỏ này:
#! /bin/sh
t="lkj"
t=${t:-2}
echo $t
Nhưng nó in chữ "lkj", tôi đang làm gì sai?
Tôi muốn xóa ký tự cuối cùng của chuỗi, tôi đã thử đoạn script nhỏ này:
#! /bin/sh
t="lkj"
t=${t:-2}
echo $t
Nhưng nó in chữ "lkj", tôi đang làm gì sai?
Câu trả lời:
Trong hệ vỏ POSIX, cú pháp ${t:-2}
có nghĩa là một cái gì đó khác - nó mở rộng thành giá trị t
if t
được đặt và không null, và ngược lại với giá trị 2
. Để cắt một ký tự bằng cách mở rộng tham số, cú pháp bạn có thể muốn là${t%?}
Lưu ý rằng trong ksh93
, bash
hoặc zsh
, ${t:(-2)}
hoặc ${t: -2}
(lưu ý khoảng trắng) là hợp pháp dưới dạng mở rộng chuỗi con nhưng có thể không phải là điều bạn muốn, vì chúng trả lại chuỗi con bắt đầu từ vị trí 2 ký tự ở cuối (nghĩa là nó loại bỏ ký tự đầu tiêni
của ký tự chuỗi ijk
).
Xem phần Mở rộng tham số Shell của Hướng dẫn tham khảo Bash để biết thêm thông tin:
${parameter%word}
loại bỏ khớp mẫu hậu tố ngắn nhất word
- xem phần Mở rộng tham số củaman bash
Với bash
4.2 trở lên, bạn có thể làm:
${var::-1}
Thí dụ:
$ a=123
$ echo "${a::-1}"
12
Lưu ý rằng đối với bản cũ hơn bash
(ví dụ: bash 3.2.5
trên OS X), bạn nên chừa khoảng trắng giữa và sau dấu hai chấm:
${var: : -1}
bash
phiên bản 4.2-alpha trở lên, quá tệ là phiên bản tôi có quyền truy cập trước đó. : - /
${var:offset:lenght}
được thêm vào bash 4.2
. Có lẽ OSX thêm bản vá của riêng mình cho bash
.
để xóa các n
ký tự cuối cùng khỏi dòng không sử dụng sed
OR awk
:
> echo lkj | rev | cut -c (n+1)- | rev
vì vậy, ví dụ bạn có thể xóa ký tự cuối cùng one character
bằng cách này:
> echo lkj | rev | cut -c 2- | rev
> lk
từ rev
trang web:
MÔ TẢ
Tiện ích rev sao chép các tệp được chỉ định vào đầu ra tiêu chuẩn, đảo ngược thứ tự các ký tự trong mỗi dòng. Nếu không có tệp nào được chỉ định, đầu vào tiêu chuẩn sẽ được đọc.
CẬP NHẬT:
nếu bạn không biết độ dài của chuỗi, hãy thử:
$ x="lkj"
$ echo "${x%?}"
lk
Sử dụng sed nên nhanh như
sed 's/.$//'
Tiếng vang duy nhất của bạn là sau đó echo ljk | sed 's/.$//'
.
Sử dụng điều này, chuỗi 1 dòng có thể có kích thước bất kỳ.
Một vài tùy chọn tùy thuộc vào vỏ:
t=${t%?}
t=`expr " $t" : ' \(.*\).'`
t=${t[1,-2]}
t=${t:0:-1}
t=${t:0:${#t}-1}
t=${t/%?}
t=${t/~(E).$/}
@ {t=$1} ~~ $t *?
Lưu ý rằng trong khi tất cả được cho là loại bỏ ký tự cuối cùng , bạn sẽ thấy rằng một số triển khai (những thứ không hỗ trợ các ký tự nhiều byte) thay vào đó là byte cuối cùng (do đó có thể sẽ làm hỏng ký tự cuối cùng nếu nó là nhiều byte ).
Các expr
biến thể giả định $t
không kết thúc với nhiều hơn một ký tự dòng mới. Nó cũng sẽ trả về trạng thái thoát khác không nếu chuỗi kết quả kết thúc bằng 0
( 000
hoặc thậm chí -0
với một số triển khai). Nó cũng có thể cho kết quả bất ngờ nếu chuỗi chứa các ký tự không hợp lệ.
t=${t%?}
không phải là Bourne nhưng hiện tại bạn không có khả năng bắt gặp một vỏ Bourne. ${t%?}
không làm việc trong tất cả những người khác mặc dù.
fish
là công việc đang tiến triển. 2.3.0 giới thiệu string
nội dung không được phát hành tại thời điểm hỏi đáp. Với phiên bản tôi đang thử nghiệm, bạn cần string replace -r '(?s).\z' '' -- $t
(và tôi mong họ muốn thay đổi điều đó, họ nên thay đổi các cờ họ chuyển sang PCRE) hoặc nhiều hơn nữa. Nó cũng xử lý kém với các nhân vật dòng mới và tôi biết họ cũng đang có kế hoạch thay đổi điều đó.
Câu trả lời ngắn gọn và di động nhất gần như chắc chắn:
${t%?}
Điều này hoạt động trong bash, sh, tro, dash, busybox / ash, zsh, ksh, v.v.
Nó hoạt động bằng cách sử dụng mở rộng tham số shell trường học cũ. Cụ thể, %
chỉ định loại bỏ hậu tố phù hợp nhỏ nhất của tham số t
khớp với mẫu hình cầu ?
(nghĩa là: bất kỳ ký tự nào).
Xem "Xóa mẫu hình hậu tố nhỏ nhất" tại đây để được giải thích chi tiết hơn (nhiều hơn) và có thêm thông tin cơ bản. Đồng thời xem tài liệu cho trình bao của bạn (ví dụ man bash
:) trong phần "mở rộng tham số".
Là một lưu ý phụ, nếu bạn muốn xóa ký tự đầu tiên thay vào đó, bạn sẽ sử dụng ${t#?}
, vì #
khớp từ phía trước của chuỗi (tiền tố) thay vì phía sau (hậu tố).
Cũng đáng chú ý là cả hai %
và #
có %%
và ##
các phiên bản, phù hợp với phiên bản dài nhất của mẫu đã cho thay vì ngắn nhất. Tuy nhiên, cả hai ${t%%?}
và ${t##?}
sẽ làm giống như toán tử đơn của chúng trong trường hợp này (vì vậy đừng thêm ký tự phụ vô dụng). Điều này là do ?
mẫu đã cho chỉ khớp với một ký tự. Kết hợp *
với một số ký tự không phải là ký tự đại diện và mọi thứ trở nên thú vị hơn với %%
và ##
.
Hiểu các mở rộng tham số, hoặc ít nhất là biết về sự tồn tại của chúng và biết cách tìm kiếm chúng, cực kỳ hữu ích để viết và giải mã các tập lệnh shell của nhiều hương vị. Mở rộng tham số thường trông giống như voodoo shell arcane đối với nhiều người bởi vì ... ờ ... chúng là voodoo shell arcane (mặc dù tài liệu khá tốt nếu bạn biết tìm "mở rộng tham số"). Mặc dù vậy, chắc chắn là tốt để có trong vành đai công cụ khi bạn bị mắc kẹt trong vỏ.
t=lkj
echo ${t:0:${#t}-1}
Bạn nhận được một chuỗi con từ 0 đến độ dài chuỗi -1. Tuy nhiên, lưu ý rằng chất nền này là đặc trưng bash và sẽ không hoạt động trên các shell khác.
Chẳng hạn, dash
không thể phân tích cú pháp
echo ${t:0:$(expr ${#t} - 1)}
Ví dụ, trên Ubuntu, /bin/sh
làdash
Chỉ cần hoàn thành một số cách sử dụng có thể của bash tinh khiết:
#!/bin/bash
# Testing substring removal
STR="Exemple string with trailing whitespace "
echo "'$STR'"
echo "Removed trailing whitespace: '${STR:0:${#STR}-1}'"
echo "Removed trailing whitespace: '${STR/%\ /}'"
Cú pháp đầu tiên lấy một chuỗi con từ một chuỗi, cú pháp là
Đối với chuỗi thứ hai, hãy chú ý dấu hiệu, có nghĩa là 'từ cuối dòng' và cú pháp là
${STRING:OFFSET:LENGTH}
%
${STRING/PATTERN/SUBSTITUTION}
Và đây là hai hình thức ngắn hơn của các đề cập ở trên
echo "Removed trailing whitespace: '${STR::-1}'"
echo "Removed trailing whitespace: '${STR%\ }'"
Ở đây thông báo lại %
dấu hiệu, có nghĩa là 'Xóa (nghĩa là thay thế bằng' ') mẫu phù hợp ngắn nhất (ở đây được biểu thị bằng không gian thoát ' \ ' từ cuối PARAMETER - ở đây có tên là STR