Wie entferne ich die letzten n Zeichen aus einer Zeichenfolge in Bash?

202

Ich habe eine Variable varin einem Bash-Skript, die eine Zeichenfolge enthält, wie:

echo $var
"some string.rtf"

Ich möchte die letzten 4 Zeichen dieser Zeichenfolge entfernen und das Ergebnis einer neuen Variablen zuweisen var2, damit

echo $var2
"some string"

Wie kann ich das machen?

winko
quelle
1
Duplikat von Extrakt-Teilzeichenfolge-in-Bash
Håkon Hægland

Antworten:

16

Zunächst sollten Sie explizit angeben, was Sie möchten. Wenn Sie wissen, dass die Zeichenfolge endet .rtfund Sie die Zeichenfolge entfernen möchten .rtf, können Sie sie verwenden var2=${var%.rtf}. Wenn Sie das Suffix nicht kennen, aber alles ab dem letzten entfernen möchten, .können Sie es verwenden var2=${var%.*}. Wenn Sie nur alles auf dem neuesten Stand halten möchten ., können Sie verwenden var2=${var%%.*}. Diese beiden letzten Optionen haben das gleiche Ergebnis, wenn es nur einen Zeitraum gibt. Wenn es jedoch mehr als einen gibt, sollten Sie entscheiden, welchen Sie möchten.

Wenn Sie wirklich immer eine genaue Anzahl von Zeichen entfernen möchten, finden Sie hier einige Optionen.

Sie haben Bash speziell angegeben, daher beginnen wir mit Bash-Buildins. Diejenige, die am längsten funktioniert hat, ist dieselbe Syntax zum Entfernen von Suffixen, die ich oben verwendet habe: Um vier Zeichen zu entfernen, verwenden Sie var2=${var%????}. Sie müssen ein Fragezeichen pro entferntem Zeichen entfernen, damit dies bei größeren Teilstringlängen unhandlich wird.

Etwas neuer ist die Teilstring-Extraktion : var2=${var::${#var}-4}. Hier können Sie eine beliebige Zahl anstelle von setzen 4, um eine andere Anzahl von Zeichen zu entfernen. (Das ${#var}wird durch die Länge der Zeichenfolge ersetzt, daher werden tatsächlich die ersten (Länge - 4) Zeichen beibehalten.)

Mit neueren Versionen von Bash (speziell 4+, dh die mit MacOS gelieferte Version funktioniert nicht) können Sie dies einfach vereinfachen var2=${var::-4}.

Wenn Sie nicht Bash verwenden, sondern eine andere POSIX-Shell, funktioniert das Entfernen von Suffixen auch in einem einfachen alten Bindestrich (wo keiner der anderen dies tut). In zsh funktionieren alle, aber Sie müssen ein 0zwischen die Doppelpunkte setzen: var2=${var:0:-4}usw. In ksh benötigen Sie die 0 und müssen auch den expliziten Ausdruck der Länge 4 verwenden : var2=${var:0:${#var}-4}.

Sie können die Befehlssubstitution natürlich auch mithilfe eines Hilfsprogramms verwenden. Es gibt viele, die funktionieren werden, aber so etwas var2=$(cut -c -4 <<<"$var")ist wahrscheinlich die kürzeste Option.

Mark Reed
quelle
240

Sie können dies tun:

#!/bin/bash

v="some string.rtf"

v2=${v::-4}

echo "$v --> $v2"
phe
quelle
9
Bash 4+ denke ich.
Etan Reisner
69
Es ist bash4+, aber in früheren Versionen können Sie die etwas länger verwenden ${v::${#v}-4}.
Chepper
8
Hat bei mir nicht funktioniert, Bash sagt "Bad Substitution"
Ivan Marjanovic
15
aus irgendeinem Grund ${v::-4}krächzt in zsh "zsh: schließende Klammer erwartet". Aber die Antwort von @fredtantini unten ${v:0:-4}funktioniert gut.
Pierre D
6
Fehler mit: -2: Teilzeichenfolgenausdruck <0
Edward
171

Um vier Zeichen am Ende der Zeichenfolge zu entfernen, verwenden Sie ${var%????}.

Alles nach dem endgültigen .Gebrauch entfernen ${var%.*}.

Etan Reisner
quelle
12
Reine Shell-Antwort und funktioniert in BASH 3.x, das auf vielen Systemen zu finden ist, die sich aufgrund von Lizenzproblemen geweigert haben, BASH 4.x zu implementieren.
David W.
1
Dies ist cool, da es robust gegen kürzere Saiten ist. Die Indexoffset-Varianten schlagen dann fehl.
Raphael
funktioniert in bash 3.2.25 - die bestmögliche Antwort - genau das, wonach ich gesucht habe
capser
Hervorragende Antwort. Wie wäre es mit einer Entfernung an der Vorderseite der Schnur?
user2023370
3
@ user2023370 Aus der Dokumentation sollte hervorgehen, dass dafür eine entsprechende Parametersubstitution vorhanden ist ${var#????}.
Tripleee
48

Was für mich funktioniert hat war:

echo "hello world" | rev | cut -c5- | rev
# hello w

Aber ich habe es verwendet, um Linien in einer Datei zu schneiden, deshalb sieht es unangenehm aus. Die wirkliche Verwendung war:

cat somefile | rev | cut -c5- | rev

cutbringt Sie nur so weit, dass Sie von einer Startposition aus trimmen, was schlecht ist, wenn Sie Zeilen mit variabler Länge benötigen. Diese Lösung kehrt also revden String um ( ) und jetzt beziehen wir uns auf seine Endposition, verwenden ihn dann cutwie erwähnt und kehren ihn (wieder rev) in seine ursprüngliche Reihenfolge zurück.

Reut Sharabani
quelle
Dies ist nicht korrekt und keine Antwort auf die Fragen. revkehrt Zeilen um, keine Zeichenfolgen. echo $SOME_VAR | rev | ...wird sich wahrscheinlich nicht so verhalten, wie man es erwarten würde.
Mohammad Nasirifar
2
@Mohammad Wegen der zitiert, gebrochen , das ist eine einzelne Zeile.
Tripleee
38

Verwenden der variablen Erweiterung / Ersetzen des Teilstrings :

$ {var /% Pattern / Replacement}

Wenn das Suffix von var mit Pattern übereinstimmt, ersetzen Sie Pattern durch Replacement.

So können Sie tun:

~$ echo ${var/%????/}
some string

Alternative,

Wenn Sie immer die gleichen 4 Buchstaben haben

~$ echo ${var/.rtf/}
some string

Wenn es immer endet mit .xyz:

~$ echo ${var%.*}
some string

Sie können auch die Länge der Zeichenfolge verwenden:

~$ len=${#var}
~$ echo ${var::len-4}
some string

oder einfach echo ${var::-4}

Fredtantini
quelle
len=${#var}; echo ${var::len-4}könnte verkürzt werden auf echo ${var:0:-4}:-) EDIT: oder wie @iyonizer betonte, nur echo ${var::-4}...
anishsane
26

Sie könnten sed verwenden,

sed 's/.\{4\}$//' <<< "$var"

Beispiel:

$ var="some string.rtf"
$ var1=$(sed 's/.\{4\}$//' <<< "$var")
$ echo $var1
some string
Avinash Raj
quelle
1
und wie ordne ich das Ergebnis zu var2?
Becko
Das ist gut, weil es in einer Zeile wie dieser funktioniert ... | sed 's /. \ {4 \} $ //'. Kann ohne Verwendung von Variablen verwendet werden
Sam
3

Ich habe folgendes versucht und es hat bei mir funktioniert:

#! /bin/bash

var="hello.c"
length=${#var}
endindex=$(expr $length - 4)
echo ${var:0:$endindex}

Ausgabe: hel

Priya Jain
quelle
1

Hoffe das folgende Beispiel wird helfen,

echo ${name:0:$((${#name}-10))} -> ${name:start:len}

  • Im obigen Befehl ist name die Variable.
  • start ist der String-Startpunkt
  • len ist die Länge der Zeichenfolge, die entfernt werden muss.

Beispiel:

    read -p "Enter:" name
    echo ${name:0:$((${#name}-10))}

Ausgabe:

    Enter:Siddharth Murugan
    Siddhar

Hinweis: Bash 4.2 hat Unterstützung für negative Teilzeichenfolgen hinzugefügt

Siddharth Murugan
quelle
Dies ist viel ausführlicher als eine Bourne-kompatible einfache Mustersubstitution wie in Etan Reisners Antwort.
Tripleee
0

Dies funktionierte für mich durch Berechnung der Größe der Zeichenfolge.
Es ist einfach, den zurückgegebenen Wert wiederzugeben und ihn dann wie unten zu speichern

removechars(){
        var="some string.rtf"
        size=${#var}
        echo ${var:0:size-4}  
    }
    removechars
    var2=$?

eine Schnur

Saurabh
quelle
0

In diesem Fall können Sie den Basisnamen verwenden, vorausgesetzt, Sie haben dasselbe Suffix für die Dateien, die Sie entfernen möchten.

Beispiel:

basename -s .rtf "some string.rtf"

Dies gibt "eine Zeichenfolge" zurück

Wenn Sie das Suffix nicht kennen und möchten, dass alles nach und einschließlich des letzten Punkts entfernt wird:

f=file.whateverthisis
basename "${f%.*}"

gibt "Datei" aus

% bedeutet hacken ,. ist, was Sie hacken, * ist Platzhalter

Greta
quelle