Zugriff auf die letzten x Zeichen einer Zeichenfolge in Bash

124

Ich fand heraus, dass man mit ${string:0:3}einem auf die ersten 3 Zeichen einer Zeichenkette zugreifen kann. Gibt es eine gleich einfache Methode, um auf die letzten drei Zeichen zuzugreifen?

Aldorado
quelle

Antworten:

235

Die letzten drei Zeichen von string:

${string: -3}

oder

${string:(-3)}

(Beachten Sie den Abstand zwischen :und -3in der ersten Form).

Weitere Informationen finden Sie in der Shell-Parametererweiterung im Referenzhandbuch :

${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.

Da diese Antwort einige regelmäßige Ansichten enthält, möchte ich eine Möglichkeit hinzufügen, auf John Rix 'Kommentar einzugehen. Wie er erwähnt, wird Ihre Zeichenfolge, wenn sie eine Länge von weniger als 3 hat, ${string: -3}zur leeren Zeichenfolge erweitert. Wenn Sie in diesem Fall die Erweiterung von möchten string, können Sie Folgendes verwenden:

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

Dies verwendet den ?:ternären if-Operator, der in Shell Arithmetic verwendet werden kann . Da der Offset, wie dokumentiert, ein arithmetischer Ausdruck ist, ist dies gültig.

gniourf_gniourf
quelle
5
Beachten Sie, dass dies nicht funktioniert, wenn Ihre Zeichenfolge kürzer als der von Ihnen angegebene negative Offset ist. In solchen Fällen erhalten Sie nur eine leere Zeichenfolge.
John Rix
2
@gniourf_gniourf Wie kann dies zusammen mit der Befehlssubstitution verwendet werden? Ich versuche, die letzten drei Zeichen meines Hostnamens zu extrahieren deppfx@localhost:/tmp$ echo ${$(hostname): -3} -bash: ${$(hostname): -3}: bad substitution
deppfx
3
@deppfx: Sie können nicht in Bash. Verwenden Sie eine temporäre Variable : temp=$(hostname); echo "${temp: -3}". Bash hat auch die HOSTNAMEVariable (die von der Ausgabe von abweichen kann oder nicht hostname). Wenn Sie es verwenden möchten, tun Sie es einfach echo "${HOSTNAME: -3}".
gniourf_gniourf
Wie können Sie dies vom Ausgang einer Pipe verwenden? Zum Beispiel some func | echo ${string: -3}- wie ordne ich die Ausgabe von some funczu string?
Michael Hays
1
@MichaelHays: Weisen Sie einfach die Ausgabe Ihrer Funktion zu: string=$(some func)und dann echo "${string: -3}".
gniourf_gniourf
48

Sie können verwenden tail:

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

Ein etwas umständlicher Weg, um die letzten drei Zeichen zu erhalten, wäre zu sagen:

echo $foo | rev | cut -c1-3 | rev
devnull
quelle
2
Der "Schwanz" ist auch im Dash nützlich, wenn Bash nicht verfügbar ist. ZB den Skriptabschnitt neu starten.
Vskubriev
13

Eine andere Problemumgehung besteht darin, grep -omit ein wenig Regex-Magie drei Zeichen zu erhalten, gefolgt vom Zeilenende:

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

Um die Option 1 bis 3 letzte Zeichen zu erhalten, können Sie bei Zeichenfolgen mit weniger als 3 Zeichen egrepFolgendes verwenden:

$ 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

Sie können auch verschiedene Bereiche verwenden, z. B. 5,10um die letzten fünf bis zehn Zeichen zu erhalten.

Aurelio Jargas
quelle
7

Um die Frage und die Antwort von gniourf_gniourf zu verallgemeinern (wie das ist , was ich suchte), wenn Sie einen schneiden möchten Bereich von Zeichen aus, sagen wir, 7. vom Ende zum dritten vom Ende, können Sie diese Syntax verwenden:

${string: -7:4}

Wobei 4 die Länge ist (7-3).

Während die Lösung von gniourf_gniourf offensichtlich die beste und sauberste ist, wollte ich nur eine alternative Lösung mit cut hinzufügen :

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

Dies ist besser lesbar, wenn Sie dies in zwei Zeilen tun, indem Sie die Länge $ {# string} als separate Variable definieren.

Adrian Tompkins
quelle
Eine Variante, die in der anderen Antwort nicht erwähnt wird, besteht darin, diesen cutAnsatz zu kombinieren, indem zuerst der Start / Stopp berechnet und dann nur diese Variablen in der Parametererweiterung verwendet werden (erwähnenswert ist auch, dass cutund Bash-Offsets bei 1 bzw. Null beginnen, sodass dies erforderlich wäre in die Berechnungen start=$((${#string}-3)); stop=$((${#string}));echo ${string: $start : $stop}echo $string | cut -c "$start"-"$stop"
einbezogen
(Oh, egal - ich sehe, dass mein Kommentar nicht das Problem anspricht, dass der String zu kurz ist und dann überhaupt keine Ausgabe verursacht - sowohl die Schnitt- als auch die String-Parametererweiterung. Trotzdem wird er in Variablen aufgeteilt ( ohne unbedingt zusätzliche Befehle zu fordern) erleichtert das Lesen und wäre immer noch eine gute Idee, denke ich.)
Michael