Come rimuovere gli ultimi n caratteri da una stringa in Bash?


202

Ho una variabile varin uno script Bash che contiene una stringa, come:

echo $var
"some string.rtf"

Voglio rimuovere gli ultimi 4 caratteri di questa stringa e assegnare il risultato a una nuova variabile var2, in modo che

echo $var2
"some string"

Come posso fare questo?


Risposte:


16

Innanzitutto, dovresti essere esplicito su ciò che desideri. Se sai che la stringa finisce .rtfe vuoi rimuoverla .rtf, puoi usarla var2=${var%.rtf}. Se non sai qual è il suffisso ma vuoi rimuovere tutto a partire dall'ultimo ., puoi usare var2=${var%.*}. Se vuoi mantenere tutto fino al primo ., puoi usarlo var2=${var%%.*}. Queste ultime due opzioni hanno lo stesso risultato se c'è un solo periodo, ma se potrebbe essercene più di uno, dovresti decidere quale vuoi.

Se vuoi davvero rimuovere sempre un numero esatto di caratteri, ecco alcune opzioni.

Hai specificato bash in modo specifico, quindi inizieremo con i builtin bash. Quello che ha funzionato più a lungo è la stessa sintassi di rimozione del suffisso che ho usato sopra: per rimuovere quattro caratteri, usare var2=${var%????}. È necessario rimuovere un punto interrogativo per carattere, quindi diventa ingombrante per lunghezze di sottostringa più grandi.

Un po 'più recente è sottoStringa estrazione: var2=${var::${#var}-4}. Qui puoi inserire qualsiasi numero al posto di 4per rimuovere un diverso numero di caratteri. ( ${#var}Viene sostituito dalla lunghezza della stringa, quindi questo in realtà chiede di mantenere i primi (lunghezza - 4) caratteri.)

Le versioni più recenti di bash (in particolare 4+, il che significa che quella fornita con MacOS non funzionerà) ti consente di semplificare questo per solo var2=${var::-4}.

Se in realtà non stai usando bash ma qualche altra shell di tipo POSIX, la rimozione del suffisso continuerà a funzionare, anche con un trattino vecchio (dove nessuno degli altri lo farà). In zsh, tutti lavorano, ma si devono mettere una 0tra le due punti: var2=${var:0:-4}ecc ksh, è necessario il 0 e hanno anche di utilizzare l'esplicito lunghezza-4 espressione: var2=${var:0:${#var}-4}.

Ovviamente puoi usare la sostituzione dei comandi per farlo con l'aiuto di un programma di utilità; ce ne sono molti che funzioneranno, ma qualcosa del genere var2=$(cut -c -4 <<<"$var")è probabilmente l'opzione più breve.


241

Puoi fare così:

#!/bin/bash

v="some string.rtf"

v2=${v::-4}

echo "$v --> $v2"

9
bash 4+ penso.
Etan Reisner,

69
È bash4+, ma nella versione precedente è possibile utilizzare il leggermente più lungo ${v::${#v}-4}.
Chepner,

8
Non ha funzionato per me, bash dice "Sostituzione
errata

15
per qualche motivo, in zsh ${v::-4}gracchiano "zsh: chiusura parentesi prevista". Ma la risposta di @fredtantini di seguito ${v:0:-4}funziona bene.
Pierre D,

6
Errore con: -2: espressione di sottostringa <0
Edward

174

Per rimuovere quattro caratteri dalla fine della stringa usare ${var%????}.

Per rimuovere tutto dopo l' .uso finale ${var%.*}.


12
Pure shell risponde e funzionerà in BASH 3.x che si trova su molti sistemi che hanno rifiutato di implementare BASH 4.x a causa di problemi di licenza.
David W.

1
Questo è fantastico poiché è robusto contro stringhe più corte; le varianti di offset dell'indice falliscono quindi.
Raffaello,

funziona in bash 3.2.25 - la migliore risposta possibile - proprio quello che stavo cercando
capser

Risposta eccellente. Che ne dici di una rimozione nella parte anteriore della corda?
user2023370

3
@ user2023370 Consultare la documentazione per rivelare che esiste una sostituzione di parametro corrispondente ${var#????}per questo.
triplo

48

Ciò che ha funzionato per me è stato:

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

Ma l'ho usato per tagliare le linee in un file, ecco perché sembra imbarazzante. Il vero utilizzo era:

cat somefile | rev | cut -c5- | rev

cutti porta solo fino a tagliare da una posizione iniziale, il che è male se hai bisogno di file di lunghezza variabile. Quindi questa soluzione inverte ( rev) la stringa e ora ci relazioniamo con la sua posizione finale, quindi la usa cutcome detto, e la inverte (di nuovo rev) di nuovo al suo ordine originale.


Questo non è corretto e non è una risposta a ciò che viene chiesto. revinverte le linee, non le stringhe. echo $SOME_VAR | rev | ...probabilmente non si comporterà come ci si aspetterebbe.
Mohammad Nasirifar,

2
@Mohammad A causa della citazione rotta, questa è una riga singola.
triplo

38

Utilizzo della sostituzione di espansione / sottostringa variabile :

$ {Var /% Modello / Sostituto}

Se il suffisso di var corrisponde a Pattern, sostituire Sostituzione per Pattern.

Quindi puoi fare:

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

In alternativa,

Se hai sempre le stesse 4 lettere

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

Se finisce sempre con .xyz:

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

Puoi anche usare la lunghezza della stringa:

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

o semplicemente echo ${var::-4}


len=${#var}; echo ${var::len-4}potrebbe essere abbreviato in echo ${var:0:-4}:-) EDIT: o come ha sottolineato @iyonizer, solo echo ${var::-4}...
anishsane il

26

Puoi usare sed,

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

Esempio:

$ var="some string.rtf"
$ var1=$(sed 's/.\{4\}$//' <<< "$var")
$ echo $var1
some string

1
e come posso assegnare il risultato a var2?
becko,

questo va bene perché funziona su una riga come questa ... | sed 's /. \ {4 \} $ //'. Può essere utilizzato senza utilizzare le variabili
Sam

3

Ho provato quanto segue e ha funzionato per me:

#! /bin/bash

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

Produzione: hel


1

Spero che l'esempio che segue sarà di aiuto,

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

  • Nel comando sopra, name è la variabile.
  • start è il punto iniziale della stringa
  • len è la lunghezza della stringa che deve essere rimossa.

Esempio:

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

Produzione:

    Enter:Siddharth Murugan
    Siddhar

Nota: Bash 4.2 ha aggiunto il supporto per la sottostringa negativa


Questo è molto più dettagliato di una semplice sostituzione del modello compatibile con Bourne come nella risposta di Etan Reisner.
triplo

0

Questo ha funzionato per me calcolando la dimensione della stringa.
È facile fare eco al valore che devi restituire e poi memorizzarlo come di seguito

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

qualche stringa


0

In questo caso è possibile utilizzare il nome di base presupponendo che si disponga dello stesso suffisso per i file che si desidera rimuovere.

Esempio:

basename -s .rtf "some string.rtf"

Questo restituirà "qualche stringa"

Se non conosci il suffisso e desideri che rimuova tutto dopo e incluso l'ultimo punto:

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

genera "file"

% significa tritare,. è ciò che stai tagliando, * è un carattere jolly

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.