Jak uzyskać znak w danej pozycji ciągu w skrypcie powłoki?


Odpowiedzi:


36

W skrócie z „Rozszerzeniem parametru” $ {parametr: offset: długość}

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

Edycja: Bez rozszerzenia parametrów (niezbyt elegancki, ale to, co przyszło do mnie jako pierwsze)

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

1
gnu.org/software/bash/manual/… ma więcej szczegółów
jsbillings


Możesz także ustawić przesunięcie „od końca” takecho ${var: -2:1}
Vassilis

Ta składnia pochodzi z ksh93 i jest również obsługiwana przez zshi mksh.
Stéphane Chazelas,

6

Alternatywą dla rozszerzania parametrów jest expr substr

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

Na przykład:

$ expr substr hello 2 1
e

fajnie, powinienem był dokładnie sprawdzić expr.
forcefsck 17.03.11

1
Chociaż wydaje się, że działa z expr z GNU coreutils, substrnie jest uwzględniony w expr z FreeBSD, NetBSD lub OS X. To nie jest przenośne rozwiązanie.
ghoti

@ghoti, zauważ, że substroryginalnie nie jest to rozszerzenie GNU. Oryginalna implementacja exprpochodzi z PWB Unix pod koniec lat 70. i miała substr(ale nie :).
Stéphane Chazelas,

@ StéphaneChazelas, dzięki za dodanie perspektywy historycznej. :) Chociaż jestem prawie pewien, że użycie PWB nie ma związku z OP, zawsze fajnie jest śledzić funkcje i zmiany przez dekady. GNU wydaje się być domyślnym ustawieniem wielu ludzi, ale generalnie myślę, że unikałbym używania opcji, które nie są wyraźnie POSIX i które są znane z tego, że zaginęły w dużych jednorożcach.
ghoti

5

cut -c

Jeśli zmienna nie zawiera znaków nowej linii, możesz:

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

wyjścia:

b

awk substr to kolejna alternatywa POSIX, która działa, nawet jeśli zmienna ma znaki nowego wiersza:

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"

wyjścia:

b

printf '%s\n'jest uniknięcie problemów ze znakami zmiany znaczenia: /programming//a/40423558/895245 np .:

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

wyniki \zgodnie z oczekiwaniami.

Zobacz także: /programming/1405611/extracting-first-two-characters-of-a-string-shell-scripting

Testowane w Ubuntu 19.04.


printf '%s' "$myvar" | cut -c2nie jest POSIX, ponieważ wynik printfnie jest tekstem, chyba że $myvarkończy się znakiem nowej linii. W przeciwnym razie zakłada, że ​​zmienna nie zawiera znaków nowej linii, ponieważ cutprzecina każdą linię jej danych wejściowych.
Stéphane Chazelas

Ten awkbyłby bardziej wydajny i niezawodny zawk -- 'BEGIN {print substr (ARGV[1], 2, 1)}' "$myvar"
Stéphane Chazelas

Należy zauważyć, że z obecnej wersji GNU cut, że nie działa dla znaków wielo-bajtowych (taki sam dla mawk lub BusyBox awk)
Stéphane Chazelas

@ StéphaneChazelas dzięki za punkty. Nie rozumiem, co masz na myśli w pierwszym: czy masz na myśli, że printf 'abc '| cut -c2to jest złe, ponieważ nie \n(o tym nie wiem), czy że polecenie nie powiedzie się, jeśli myvar ma nowe linie (zgadzam się)?
Ciro Santilli 新疆 改造 中心 法轮功 六四 事件

1
Zachowanie nie cutjest określone, jeśli dane wejściowe nie są tekstem (choć cutimplementacje są wymagane do obsługi wierszy lub dowolnej długości). Wynik printf abcnie jest tekstem, ponieważ nie kończy się znakiem nowego wiersza. W praktyce, w zależności od implementacji, jeśli to zrobisz cut -c2, dostaniesz albo nic b, b<newline>albo wcale. Trzeba by printf 'abc\n' | cut -c2uzyskać zachowanie określone przez POSIX (wymagane do wyjścia b<newline>)
Stéphane Chazelas

1

Z zshlub yashużyłbyś:

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

(w zsh, możesz go skrócić printf '%s\n' $text[3]).


0

Możesz użyć polecenia cięcia. Aby uzyskać trzecią pozycję:

echo "SAMPLETEXT" | cut -c3

Sprawdź ten link http://www.folkstalk.com/2012/02/cut-command-in-unix-linux-examples.html

( Przypadki zaawansowane ) Jednak modyfikacja IFS jest również dobrą rzeczą, szczególnie gdy twoje dane wejściowe mogą zawierać spacje. Tylko w takim przypadku skorzystaj z poniższego

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

Nie widzę, jak IFSby się to grało w opublikowanym kodzie.
Kusalananda
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.