Elimina l'ultimo carattere di una stringa usando la manipolazione della stringa nello script della shell


187

Vorrei cancellare l'ultimo carattere di una stringa, ho provato questo piccolo script:

#! /bin/sh 

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

ma stampa "lkj", cosa sto facendo di sbagliato?

Risposte:


115

In una shell POSIX, la sintassi ${t:-2}significa qualcosa di diverso: si espande al valore di tif tè impostato e non nullo, e altrimenti al valore 2. Per tagliare un singolo carattere in base all'espansione dei parametri, la sintassi che probabilmente desideri è${t%?}

Si noti che in ksh93, basho zsh, ${t:(-2)}o ${t: -2}(notare lo spazio) sono legali come espansione di sottostringa ma probabilmente non sono ciò che si desidera, poiché restituiscono la sottostringa a partire da una posizione di 2 caratteri dalla fine (ovvero rimuove il primo carattere idi stringa ijk).

Vedi la sezione Espansione dei parametri Shell del Manuale di riferimento di Bash per maggiori informazioni:


4
Ti andrebbe di spiegare qual è la magia dietro '%?' ?
Afraisse,

8
@afraisse ${parameter%word}rimuove la corrispondenza del pattern suffisso più breve word- vedere la sezione Espansione dei parametri diman bash
steeldriver

3
Questo funziona bene con Bash 4.1.2: $ {t%?} Per le persone bloccate con CentOS / RHEL 6.x
Joey T

185

Con la versione bash4.2 e successive, puoi fare:

${var::-1}

Esempio:

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

Si noti che per i più vecchi bash(ad esempio, bash 3.2.5su OS X), è necessario lasciare spazi tra e dopo i due punti:

${var: : -1}

13
Funziona con la bashversione 4.2-alpha e successive, peccato che la versione a cui ho accesso sia precedente. : - /
hjk

2
@iamaziz: dal log delle modifiche di bash, la lunghezza negativa in è ${var:offset:lenght}stata aggiunta solo in bash 4.2. Forse OSX aggiunge la propria patch per bash.
cuonglm,

1
@cuonglm né funziona: /
iamaziz

1
Non funziona su Mac.
shinzou,

1
MACsters, guarda in basso la risposta di Russ
P

67

per rimuovere gli ultimi ncaratteri da una riga che non utilizza sedOR awk:

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

quindi ad esempio puoi eliminare l'ultimo carattere one characterusando questo:

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

> lk

dalla revmanpage:

DESCRIZIONE
L'utilità rev copia i file specificati nell'output standard, invertendo l'ordine dei caratteri in ogni riga. Se non viene specificato alcun file, viene letto l'input standard.

AGGIORNARE:

se non conosci la lunghezza della stringa, prova:

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

62

Usando sed dovrebbe essere veloce come

sed 's/.$//'

Il tuo unico eco è quindi echo ljk | sed 's/.$//'.
Usando questo, la stringa di 1 riga potrebbe essere di qualsiasi dimensione.


10
Si noti che, nel caso generale, non cancella l'ultimo carattere della stringa , ma l'ultimo carattere di ogni riga della stringa .
Stéphane Chazelas,

44

Alcune opzioni a seconda della 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 *?

Si noti che mentre tutti dovrebbero spogliare l'ultimo carattere , scoprirete che alcune implementazioni (quelle che non supportano i caratteri multi-byte) rimuovono invece l'ultimo byte (quindi probabilmente corromperebbe l'ultimo carattere se fosse multi-byte ).

La exprvariante presuppone $tche non finisca con più di un carattere di nuova riga. Restituirà anche uno stato di uscita diverso da zero se la stringa risultante finisce per essere 0(o 000o anche -0con alcune implementazioni). Potrebbe anche dare risultati imprevisti se la stringa contiene caratteri non validi.


Bello e accurato! Ma ... suppongo che tutte quelle shell supportino POSIX, quindi tutti dovrebbero semplicemente usarlo per essere il più portatile. Anche il numero di caratteri più piccolo!
Russ,

@Russ, t=${t%?}non è Bourne ma al giorno d'oggi non ti imbatterai in una shell Bourne. ${t%?}funziona in tutti gli altri però.
Stéphane Chazelas,

Nessuna opzione di conchiglia di pesce fornita! Probabilmente più popolare in questi giorni rispetto a ksh93 ...
rien333,

@ rien333. Aspetterei che l'interfaccia si stabilizzi un po '. fishè in corso di elaborazione. 2.3.0 che ha introdotto il stringbuiltin non è stato rilasciato al momento del Q&A. Con la versione su cui sto testando, è necessario string replace -r '(?s).\z' '' -- $t(e mi aspetto che vorrebbero cambiarlo, dovrebbero cambiare le bandiere che passano a PCRE) o più contorte. Si occupa anche male dei personaggi newline e so che stanno pianificando di cambiare anche quello.
Stéphane Chazelas il

Eseguito l'upgrade per la risposta POSIX. ha confermato di lavorare su Bash 3.2.57 (1)
Avindra Goolcharan il

26

La risposta più portatile e più breve è quasi certamente:

${t%?}

Funziona in bash, sh, ash, trattino, busybox / ash, zsh, ksh, ecc.

Funziona utilizzando l'espansione dei parametri della shell della vecchia scuola. In particolare, %specifica di rimuovere il più piccolo suffisso di corrispondenza del parametro tche corrisponde al modello glob ?(cioè: qualsiasi carattere).

Vedere "Rimuovi modello suffisso più piccolo" qui per una spiegazione (molto) più dettagliata e più sfondo. Vedi anche i documenti per la tua shell (ad es . man bash:) sotto "espansione dei parametri".


Come nota a margine, se si desidera rimuovere invece il primo carattere, è necessario utilizzare ${t#?}, poiché le #corrispondenze dalla parte anteriore della stringa (prefisso) anziché dalla parte posteriore (suffisso).

Vale anche la pena notare che entrambi %e #hanno %%e ##versioni, che corrispondono alla versione più lunga del modello dato anziché alla più breve. Entrambi ${t%%?}e ${t##?}farebbero lo stesso del loro singolo operatore in questo caso, però (quindi non aggiungere l'inutile carattere extra). Questo perché il ?modello dato corrisponde solo a un singolo carattere. Mescola in a *con alcuni caratteri jolly e le cose diventano più interessanti con %%e ##.

Comprendere le espansioni dei parametri, o almeno conoscere la loro esistenza e sapere come cercarle, è incredibilmente utile per scrivere e decifrare script di shell di molti gusti. Le espansioni di parametri spesso sembrano voodoo di shell arcane per molte persone perché ... beh ... sono voodoo di shell arcane (anche se abbastanza ben documentate se si sa cercare "espansione di parametri"). Sicuramente bello avere nella cintura degli attrezzi quando sei bloccato in un guscio, però.


Breve e dolce, e funziona sia su MacOS che su Linux!
dbernard il

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

Si ottiene una sottostringa da 0 alla lunghezza della stringa -1. Si noti tuttavia che questa sottostrazione è specifica bash e non funzionerà su altre shell.

Ad esempio, dashnon è in grado di analizzare nemmeno

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

Ad esempio, su Ubuntu /bin/shèdash


15

Puoi anche usare headper stampare tutto tranne l'ultimo carattere.

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

Ma sfortunatamente alcune versioni di headnon includono l' -opzione principale . Questo è il caso di headciò che viene fornito con OS X.


5

È abbastanza facile fare usando l'espressione regolare:

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

5

Alcuni perfezionamenti. Per rimuovere più di un carattere, è possibile aggiungere più punti interrogativi. Ad esempio, per rimuovere gli ultimi due caratteri dalla variabile:, $SRC_IP_MSGè possibile utilizzare:

SRC_IP_MSG=${SRC_IP_MSG%??}

4

Solo per completare alcuni possibili utilizzi di puro bash:

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

La prima sintassi prende una sottostringa da una stringa, la sintassi è Per la seconda, nota il segno, che significa "dalla fine della linea" e la sintassi è
${STRING:OFFSET:LENGTH}
%
${STRING/PATTERN/SUBSTITUTION}

E qui ci sono due forme più brevi di quanto sopra menzionato

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

Qui notate di nuovo il %segno, che significa 'Rimuovi (cioè sostituisci con' ') il modello abbinato più breve (qui rappresentato dallo spazio di escape ' \ ' dalla fine del PARAMETRO - qui chiamato STR


1

Come possiamo anche usare php nella riga di comando o script di shell. A volte è utile per l'analisi chirurgica.

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

Con tubazioni:

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

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.