Chciałbym usunąć ostatni znak ciągu, wypróbowałem ten mały skrypt:
#! /bin/sh
t="lkj"
t=${t:-2}
echo $t
ale wypisuje „lkj”, co robię źle?
Chciałbym usunąć ostatni znak ciągu, wypróbowałem ten mały skrypt:
#! /bin/sh
t="lkj"
t=${t:-2}
echo $t
ale wypisuje „lkj”, co robię źle?
Odpowiedzi:
W powłoce POSIX składnia ${t:-2}
oznacza coś innego - rozwija się do wartości t
if t
jest ustawiona i różna od null, a w przeciwnym razie do wartości 2
. Aby przyciąć pojedynczy znak poprzez rozwinięcie parametru, prawdopodobnie potrzebna jest składnia${t%?}
Zauważ, że w ksh93
, bash
albo zsh
, ${t:(-2)}
albo ${t: -2}
(uwaga przestrzeni) są prawną jako ekspansji podciągu ale prawdopodobnie nie są, co chcesz, ponieważ zwracają podciąg rozpoczynający się w położeniu 2 znaki od końca (czyli usuwa pierwszy znak i
z następujących ciąg ijk
).
Aby uzyskać więcej informacji, zobacz sekcję Rozszerzanie parametrów powłoki podręcznika Bash Reference:
${parameter%word}
usuwa najkrótsze dopasowanie wzorca sufiksu word
- patrz sekcja Rozbudowa parametruman bash
W wersji bash
4.2 i nowszej możesz:
${var::-1}
Przykład:
$ a=123
$ echo "${a::-1}"
12
Zauważ, że w przypadku starszych bash
(na przykład bash 3.2.5
w systemie OS X) należy pozostawić spacje między dwukropkami i po nich:
${var: : -1}
bash
wersji 4.2-alfa i wyższej, szkoda, że wersja, do której mam dostęp, jest wcześniejsza. : - /
${var:offset:lenght}
została dodana tylko w bash 4.2
. Może OSX doda własną łatkę bash
.
do usuwania ostatnich n
znaków z linii, która nie używa sed
OR awk
:
> echo lkj | rev | cut -c (n+1)- | rev
więc na przykład możesz usunąć ostatni znak, one character
używając tego:
> echo lkj | rev | cut -c 2- | rev
> lk
ze rev
strony man:
OPIS
Narzędzie rev kopiuje określone pliki na standardowe wyjście, odwracając kolejność znaków w każdym wierszu. Jeśli nie określono żadnych plików, standardowe wejście jest odczytywane.
AKTUALIZACJA:
jeśli nie znasz długości łańcucha, spróbuj:
$ x="lkj"
$ echo "${x%?}"
lk
Używanie sed powinno być tak szybkie jak
sed 's/.$//'
Twoje pojedyncze echo jest wtedy echo ljk | sed 's/.$//'
.
Korzystając z tego, łańcuch 1-liniowy może mieć dowolny rozmiar.
Kilka opcji w zależności od powłoki:
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 *?
Zauważ, że chociaż wszystkie powinny usuwać ostatni znak , niektóre implementacje (te, które nie obsługują znaków wielobajtowych) usuwają zamiast tego ostatni bajt (więc prawdopodobnie uszkodziłby ostatni znak, jeśli byłby wielobajtowy ).
expr
Wariant zakłada $t
nie kończy się w więcej niż jeden znak nowej linii. Zwróci również niezerowy status wyjścia, jeśli powstały ciąg będzie 0
( 000
lub nawet -0
z niektórymi implementacjami). Może również dawać nieoczekiwane wyniki, jeśli ciąg znaków zawiera nieprawidłowe znaki.
t=${t%?}
to nie Bourne, ale w dzisiejszych czasach raczej nie spotkasz powłoki Bourne'a. ${t%?}
działa jednak we wszystkich pozostałych.
fish
jest w toku. 2.3.0, która wprowadziła string
wbudowaną wersję, nie została wydana w czasie pytań i odpowiedzi. W wersji, na której testuję, potrzebujesz string replace -r '(?s).\z' '' -- $t
(i spodziewałbym się, że chcieliby to zmienić, powinni zmienić flagi, które przekazują do PCRE) lub bardziej skomplikowane. Słabo radzi sobie również z postaciami nowej linii i wiem, że planują to również zmienić.
Najbardziej przenośna i najkrótsza odpowiedź to prawie na pewno:
${t%?}
Działa to w bash, sh, ash, dash, busybox / ash, zsh, ksh itp.
Działa przy użyciu old-schoolowego rozszerzenia parametrów powłoki. W szczególności %
określa, aby usunąć najmniejszy zgodny sufiks parametru, t
który pasuje do wzorca globalnego ?
(tj. Dowolny znak).
Zobacz „Usuń najmniejszy wzór sufiksu” tutaj, aby uzyskać (znacznie) bardziej szczegółowe wyjaśnienie i dodatkowe tło. Zobacz także dokumentację swojej powłoki (np . man bash
:) w „rozszerzaniu parametrów”.
Na marginesie, jeśli zamiast tego chcesz usunąć pierwszy znak, użyj go ${t#?}
, ponieważ #
dopasowania z przodu łańcucha (przedrostek) zamiast z tyłu (przyrostek).
Warto również zauważyć, że zarówno %
i #
mają %%
i ##
wersje, które pasują do najdłuższej wersji danego wzorca zamiast najkrótszej. Oba ${t%%?}
i ${t##?}
w tym przypadku zrobiłyby to samo, co ich pojedynczy operator (więc nie dodawaj niepotrzebnego dodatkowego znaku). Jest tak, ponieważ podany ?
wzorzec pasuje tylko do jednego znaku. Wymieszaj *
z kilkoma symbolami wieloznacznymi i rzeczy stają się bardziej interesujące z %%
i ##
.
Zrozumienie rozszerzeń parametrów, a przynajmniej wiedza o ich istnieniu i umiejętność ich wyszukiwania, jest niezwykle przydatna do pisania i deszyfrowania skryptów powłoki wielu smaków. Rozszerzenia parametrów często wyglądają jak tajemne voodoo dla wielu ludzi, ponieważ ... no cóż ... są tajemnymi voodoo shellami (chociaż całkiem dobrze udokumentowane, jeśli wiesz, jak szukać „rozszerzenia parametrów”). Zdecydowanie dobrze jest mieć pasek narzędzi, gdy utkniesz w skorupie.
t=lkj
echo ${t:0:${#t}-1}
Otrzymasz podciąg od 0 do długości łańcucha -1. Zauważ jednak, że to odejmowanie jest specyficzne dla bash i nie będzie działać na innych powłokach.
Na przykład dash
nie jest w stanie nawet parsować
echo ${t:0:$(expr ${#t} - 1)}
Na przykład w systemie Ubuntu /bin/sh
jestdash
Możesz także użyć head
do wydrukowania wszystkich znaków oprócz ostatniego.
$ s='i am a string'
$ news=$(echo -n $s | head -c -1)
$ echo $news
i am a strin
Ale niestety niektóre wersje head
nie zawierają wiodącej -
opcji. Tak jest w przypadku head
systemu OS X.
Aby ukończyć niektóre możliwe zastosowania czystej bash:
#!/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/%\ /}'"
Pierwsza składnia pobiera podciąg z ciągu, składnia to
Dla drugiego zauważ znak, który oznacza „z końca linii”, a składnia to
${STRING:OFFSET:LENGTH}
%
${STRING/PATTERN/SUBSTITUTION}
A oto dwie krótsze formy wyżej wymienionych
echo "Removed trailing whitespace: '${STR::-1}'"
echo "Removed trailing whitespace: '${STR%\ }'"
Tutaj zauważ ponownie %
znak oznaczający „Usuń (to znaczy zamień na”) najkrótszy dopasowany wzór (tutaj reprezentowany przez spację „\” z końca PARAMETRU - tutaj o nazwie STR