Exclui o último caractere de uma string usando manipulação de string no shell script

152

Gostaria de excluir o último caractere de uma string, tentei este pequeno script:

#! /bin/sh 

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

mas imprime "lkj", o que estou fazendo errado?

    
por user3581976 13.07.2014 / 15:29

14 respostas

96

Em um shell POSIX, a sintaxe ${t:-2} significa algo diferente - ela se expande para o valor de t se t estiver definido e não nulo e, caso contrário, para o valor 2 . Para cortar um único caractere por expansão de parâmetro, a sintaxe que você provavelmente deseja é ${t%?}

Observe que em ksh93 , bash ou zsh , ${t:(-2)} ou ${t: -2} (observe o espaço) são legais como uma expansão de substring, mas provavelmente não são o que você deseja , uma vez que eles retornam a substring começando em uma posição a 2 caracteres do final (isto é, remove o caractere primeiro i da string ijk ).

Veja a seção de Expansão de Parâmetros Shell do Manual de Referência do Bash para mais informações:

por 13.07.2014 / 16:08
155

Com bash 4.2 e acima, você pode fazer:

${var::-1}

Exemplo:

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

Observe que, para o antigo bash (por exemplo, bash 3.2.5 no OS X), você deve deixar espaços entre e depois do cólon:

${var: : -1}
    
por 13.07.2014 / 19:29
51

para remover os últimos% caracteres n de uma linha que não faz uso de sed OR awk :

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

por exemplo, você pode excluir o último caractere one character usando:

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

> lk

de rev manpage:

DESCRIPTION
The rev utility copies the specified files to the standard output, reversing the order of characters in every line. If no files are speci- fied, the standard input is read.

ATUALIZAÇÃO:

se você não souber o comprimento da string, tente:

$ x="lkj"
$ echo "${x%?}"
lk
    
por 13.07.2014 / 15:43
36

Algumas opções dependendo do 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 *?

Note que, embora todos devam eliminar o último caractere , você descobrirá que algumas implementações (aquelas que não suportam caracteres de múltiplos bytes) eliminam o último byte (em vez disso, provavelmente corromperia o último caractere se fosse multi-byte).

A variante expr assume que $t não termina em mais de um caractere de nova linha. Ele também retornará um status de saída diferente de zero se a string resultante for 0 (ou 000 ou mesmo -0 com algumas implementações). Ele também pode fornecer resultados inesperados se a string contiver caracteres inválidos.

    
por 01.02.2016 / 11:19
32

Usando o sed, ele deve ser tão rápido quanto

sed 's/.$//'

Seu único echo é, então, echo ljk | sed 's/.$//' .
Usando isso, a string de 1 linha poderia ser de qualquer tamanho.

    
por 16.09.2015 / 10:07
16
t=lkj
echo ${t:0:${#t}-1}

Você obtém uma substring de 0 para o tamanho da string -1. Note, entretanto, que esta subtração é bash específica e não funcionará em outras shells.

Por exemplo, dash não consegue analisar nem

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

Por exemplo, no Ubuntu, /bin/sh é dash

    
por 13.07.2014 / 20:22
16

A resposta mais portátil e mais curta é quase certamente:

${t%?}

Isso funciona no bash, sh, ash, traço, busybox / ash, zsh, ksh, etc.

Funciona usando a expansão de parâmetros shell da velha escola. Especificamente, o % especifica a remoção do menor sufixo correspondente do parâmetro t que corresponde ao padrão de glob ? (ou seja, qualquer caractere).

Consulte "Remover o menor padrão de sufixos" aqui para ver um (muito) mais detalhado explicação e mais fundo. Veja também os documentos para o seu shell (por exemplo: man bash ) em "expansão de parâmetro".

Como observação, se você quiser remover o caractere primeiro , use ${t#?} , pois # corresponde da frente da string (prefixo) em vez da parte de trás (sufixo).

Também vale a pena notar que % e # têm %% e ## versões, que correspondem à versão mais longa do padrão fornecido, em vez do mais curto. No entanto, tanto ${t%%?} quanto ${t##?} farão o mesmo que seu operador único (portanto, não inclua o caractere extra inútil). Isso ocorre porque o padrão ? fornecido corresponde apenas a um único caractere. Misture em * com alguns caracteres não-curingas e as coisas ficarão mais interessantes com %% e ## .

Entender as expansões de parâmetros, ou pelo menos saber sobre sua existência e saber como pesquisá-las, é incrivelmente útil para escrever e decifrar scripts de shell de muitos tipos. As expansões de parâmetro muitas vezes se parecem com o voodoo arcano de shell para muitas pessoas porque ... bem ... elas são voodoo de shell arcano (embora muito bem documentadas se você souber procurar por "expansão de parâmetro"). Definitivamente bom ter no cinto de ferramentas quando você está preso em um shell, no entanto.

    
por 16.09.2016 / 06:49
13

Você também pode usar head para imprimir todos menos o último caractere.

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

Mas infelizmente algumas versões de head não incluem a opção - inicial. Este é o caso para o head que vem com o OS X.

    
por 10.07.2015 / 19:31
4

Obrigado SteelDriver e Networker!

se você não souber o comprimento da string, tente:

$ x="lkj"
$ echo "${x%?}"
lk
    
por 26.11.2014 / 23:23
3

É fácil de usar usando expressões regulares:

n=2
echo "lkj" | sed "s/\(.*\).\{$n\}//"
    
por 13.07.2014 / 15:49
3

Alguns refinamentos. Para remover mais de um caractere, você pode adicionar vários pontos de interrogação. Por exemplo, para remover os dois últimos caracteres da variável: $SRC_IP_MSG , você pode usar:

SRC_IP_MSG=${SRC_IP_MSG%??}
    
por 01.02.2016 / 10:54
1

Apenas para completar alguns usos possíveis do bash puro:

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

A primeira sintaxe usa uma substring de uma string, a sintaxe é de ${STRING:OFFSET:LENGTH}
Para o segundo, observe o sinal % , que significa "de fim de linha", e a sintaxe é ${STRING/PATTERN/SUBSTITUTION}

E aqui estão duas formas mais curtas do acima mencionado

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

Aqui, observe novamente o sinal % , que significa "Remover (ou seja, substituir por '') o padrão correspondente mais curto (aqui representado por espaço com escape '\' do final do PARAMETER - aqui chamado STR

    
por 26.09.2017 / 19:17
1

Como também podemos usar php na linha de comando, ou scripts de shell. Às vezes é útil para análise cirúrgica.

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

Com tubulação:

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

Em ksh:

echo ${ORACLE_SID/%?/}
    
por 12.04.2016 / 06:15