it-swarm.com.de

Löschen Sie das letzte Zeichen einer Zeichenfolge mithilfe der Zeichenfolgenmanipulation im Shell-Skript

Ich möchte das letzte Zeichen einer Zeichenfolge löschen. Ich habe dieses kleine Skript ausprobiert:

#! /bin/sh 

t="lkj"
t=${t:-2}
echo $t

aber es druckt "lkj", was mache ich falsch?

207
user3581976

In einer POSIX-Shell bedeutet die Syntax ${t:-2} Etwas anderes - sie wird auf den Wert t erweitert, wenn t gesetzt und nicht null ist, andernfalls auf den Wert 2. Um ein einzelnes Zeichen durch Parametererweiterung zu trimmen, möchten Sie wahrscheinlich ${t%?}

Beachten Sie, dass in ksh93bash oder zsh, ${t:(-2)} oder ${t: -2} (Beachten Sie das Leerzeichen) are legal als Teilstring-Erweiterung, aber wahrscheinlich nicht das, was Sie wollen, da sie den Teilstring ab einer Position von 2 Zeichen vom Ende zurückgeben (dh das zuerst Zeichen i der Zeichenfolge ijk).

Weitere Informationen finden Sie im Abschnitt zur Erweiterung der Shell-Parameter im Bash-Referenzhandbuch:

122
steeldriver

Mit bash 4.2 und höher können Sie Folgendes tun:

${var::-1}

Beispiel:

$ a=123
$ echo "${a::-1}"
12

Beachten Sie, dass für ältere bash (zum Beispiel bash 3.2.5 unter OS X) sollten Sie Leerzeichen zwischen und nach Doppelpunkten lassen:

${var: : -1}
211
cuonglm

Mit sed sollte es so schnell sein wie

sed 's/.$//'

Dein Single Echo ist dann echo ljk | sed 's/.$//'.
Damit kann die 1-zeilige Zeichenfolge eine beliebige Größe haben.

70

zum Entfernen der letzten n Zeichen aus einer Zeile, in der sed OR awk nicht verwendet wird:

> echo lkj | rev | cut -c (n+1)- | rev

so können Sie beispielsweise das letzte Zeichen one character folgendermaßen löschen:

> echo lkj | rev | cut -c 2- | rev

> lk

von rev manpage:

BESCHREIBUNG
Das Dienstprogramm rev kopiert die angegebenen Dateien in die Standardausgabe und kehrt die Reihenfolge der Zeichen in jeder Zeile um. Wenn keine Dateien angegeben sind, wird die Standardeingabe gelesen.

AKTUALISIEREN:

wenn Sie die Länge der Zeichenfolge nicht kennen, versuchen Sie:

$ x="lkj"
$ echo "${x%?}"
lk
70
Nidal

Einige Optionen je nach Shell:

  • POSIX: t=${t%?}
  • Bourne: t=`expr " $t" : ' \(.*\).'`
  • zsh/yash: t=${t[1,-2]}
  • bash/zsh: t=${t:0:-1}
  • ksh93/bash/zsh/mksh: t=${t:0:${#t}-1}
  • ksh93/bash/zsh/mksh: t=${t/%?}
  • ksh93: t=${t/~(E).$/}
  • es: @ {t=$1} ~~ $t *?

Beachten Sie, dass, während alle das letzte Zeichen entfernen sollen, Sie feststellen werden, dass einige Implementierungen (diejenigen, die keine Mehrbyte-Zeichen unterstützen) stattdessen das letzte Byte entfernen (würde also wahrscheinlich das letzte Zeichen beschädigen, wenn es ein Multi-Byte wäre).

Die Variante expr geht davon aus, dass $t Nicht mit mehr als einem Zeilenumbruch endet. Es wird auch ein Exit-Status ungleich Null zurückgegeben, wenn die resultierende Zeichenfolge 0 (Oder 000 Oder bei einigen Implementierungen sogar -0 Ist). Es kann auch zu unerwarteten Ergebnissen kommen, wenn die Zeichenfolge ungültige Zeichen enthält.

50

Die tragbarste und kürzeste Antwort lautet mit ziemlicher Sicherheit:

${t%?}

Dies funktioniert in Bash, Sh, Ash, Dash, Busybox/Ash, Zsh, Ksh usw.

Es funktioniert mithilfe der Shell-Parametererweiterung der alten Schule. Insbesondere gibt % An, dass das kleinste übereinstimmende Suffix des Parameters t entfernt werden soll, das dem Glob-Muster ? Entspricht (dh: ein beliebiges Zeichen).

Siehe "Kleinstes Suffixmuster entfernen" hier für eine (viel) detailliertere Erklärung und mehr Hintergrundinformationen. Siehe auch die Dokumente für Ihre Shell (zB: man bash) Unter "Parametererweiterung".


Als Randnotiz, wenn Sie stattdessen das erste Zeichen entfernen möchten, würden Sie ${t#?} Verwenden, da # stimmt von der Vorderseite der Zeichenfolge (Präfix) anstelle der Rückseite (Suffix) überein.

Erwähnenswert ist auch, dass sowohl % Als auch # Versionen mit %% Und ## Haben, die mit der längsten Version des angegebenen Musters anstelle des kürzesten. Sowohl ${t%%?} Als auch ${t##?} Würden in diesem Fall jedoch dasselbe tun wie ihr einzelner Operator (fügen Sie also nicht das nutzlose zusätzliche Zeichen hinzu). Dies liegt daran, dass das angegebene Muster ? Nur einem einzelnen Zeichen entspricht. Mischen Sie einen * Mit einigen Nicht-Platzhaltern und die Dinge werden mit %% Und ## Interessanter.

Das Verstehen von Parametererweiterungen oder zumindest das Wissen über ihre Existenz und das Nachschlagen ist unglaublich nützlich, um Shell-Skripte mit vielen Varianten zu schreiben und zu entschlüsseln. Parametererweiterungen sehen für viele Menschen oft wie arkanes Shell-Voodoo aus, weil ... nun ... sie arkanes Shell-Voodoo sind (obwohl sie, wenn Sie wissen, ziemlich gut dokumentiert sind nach "Parametererweiterung" suchen). Auf jeden Fall gut im Werkzeuggürtel zu haben, wenn Sie in einer Shell stecken.

36
Russ
t=lkj
echo ${t:0:${#t}-1}

Sie erhalten eine Teilzeichenfolge von 0 bis zur Zeichenfolgenlänge -1. Beachten Sie jedoch, dass diese Subtraktion bash-spezifisch ist und bei anderen Shells nicht funktioniert.

Zum Beispiel kann dash nicht einmal analysieren

echo ${t:0:$(expr ${#t} - 1)}

Zum Beispiel unter Ubuntu /bin/sh ist dash

18
Ángel

Sie können auch head verwenden, um alle bis auf das letzte Zeichen auszudrucken.

$ s='i am a string'
$ news=$(echo -n $s | head -c -1)
$ echo $news
i am a strin

Leider enthalten einige Versionen von head nicht das führende - Möglichkeit. Dies ist der Fall für das head, das mit OS X geliefert wird.

15
greenbeansugar

Es ist einfach genug, reguläre Ausdrücke zu verwenden:

n=2
echo "lkj" | sed "s/\(.*\).\{$n\}/\1/"
6
unxnut

Vielen Dank an SteelDriver und Networker!

wenn Sie die Länge der Zeichenfolge nicht kennen, versuchen Sie:

$ x="lkj"
$ echo "${x%?}"
lk
6
drill

Einige Verfeinerungen. Um mehr als ein Zeichen zu entfernen, können Sie mehrere Fragezeichen hinzufügen. So entfernen Sie beispielsweise die letzten beiden Zeichen aus der Variablen: $SRC_IP_MSG können Sie verwenden:

SRC_IP_MSG=${SRC_IP_MSG%??}
6
yuliskov

Nur um einige mögliche Verwendungen von Pure Bash zu vervollständigen:

#!/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/%\ /}'"

Die erste Syntax übernimmt einen Teilstring aus einem String, die Syntax lautet
${STRING:OFFSET:LENGTH}
Beachten Sie beim zweiten das % Zeichen, was "vom Zeilenende" bedeutet und die Syntax lautet
${STRING/PATTERN/SUBSTITUTION}

Und hier sind zwei kürzere Formen der oben genannten

echo "Removed trailing whitespace: '${STR::-1}'"
echo "Removed trailing whitespace: '${STR%\ }'"

Beachten Sie hier noch einmal die % Zeichen, was bedeutet 'Entfernen (dh durch' 'ersetzen) das kürzeste übereinstimmende Muster (hier dargestellt durch maskiertes Leerzeichen = '\' vom Ende des Parameters [~ # ~] [~ # ~] - hier benannt [~ # ~] str [~ # ~]

4
CermakM

Da können wir auch php in der Kommandozeile oder in Shell-Skripten verwenden. Es ist manchmal nützlich für die chirurgische Analyse.

php -r "echo substr('Hello', 0, -1);" 
// Output hell

Mit Rohrleitungen:

echo "hello" | php -r "echo substr(trim(fgets(STDIN)), 0, -1);"
// Output hell
1
NVRM