Como obter o último caractere de uma string em um shell?


125

Eu escrevi as seguintes linhas para obter o último caractere de uma string:

str=$1
i=$((${#str}-1))
echo ${str:$i:1}

Funciona para abcd/:

$ bash last_ch.sh abcd/
/

Não funciona paraabcd* :

$ bash last_ch.sh abcd*
array.sh assign.sh date.sh dict.sh full_path.sh last_ch.sh

Ele lista os arquivos na pasta atual .

Respostas:


95

Essa é uma das razões pelas quais você precisa citar suas variáveis:

echo "${str:$i:1}"

Caso contrário, o bash expande a variável e, nesse caso, brilha antes de imprimir. Também é melhor citar o parâmetro para o script (caso você tenha um nome de arquivo correspondente):

sh lash_ch.sh 'abcde*'

Veja também a ordem das expansões no manual de referência do bash . As variáveis ​​são expandidas antes da expansão do nome do arquivo.

Para obter o último caractere, você deve apenas usar -1como índice, uma vez que os índices negativos contam desde o final da string:

echo "${str: -1}"

O espaço após os dois pontos ( :) é NECESSÁRIO.

Essa abordagem não funcionará sem o espaço.


62
BTW, índices negativos contam da direita, então "${1: -1}"é o suficiente.
choroba

7
Você deve responder como solução formal, não aqui nos comentários.
BMW

FYI: você também pode fazer isso em um "one-liner" como echo "${str:$((${#str}-1)):1}". Isso permite que você varie os caracteres finais retornados também. Este trabalho para mim no bash v4.1.0 (1)
SaxDaddy

16
@ Resposta do choroba: Observe o espaço maldito! Isso sempre tropeça me up: "${1:-1}não funciona "!
mxmlnkn

192

Por @perreal, citar variáveis ​​é importante, mas porque li este post 5 vezes antes de encontrar uma abordagem mais simples para a questão em questão nos comentários ...

str='abcd/'
echo "${str: -1}"

Resultado: /

str='abcd*'
echo "${str: -1}"

Resultado: *

Obrigado a todos que participaram disso acima; Adicionei + 1s apropriadamente em todo o segmento!


25
Nota: observe o espaço interno ${std: -1}, sem o espaço isso não funcionará. Eu me deparei com isso e descobri que ${std:~0}também funciona (com ou sem espaço). Não tenho certeza se esse é um comportamento documentado, porém, não me preocupei em procurá-lo.
Bart

4
está documentado. homem festa diz: As expressões aritméticas de partida com um - devem ser separados por espaços em branco a partir da anterior: a ser distinguido do uso valores padrão de expansão
mighq

3
Isso é incrível, obrigado por compartilhar. A página de manual do BASH é quase esmagadora de ler, eu já estive lá várias vezes. Eu acho que eles poderiam fazer um curso universitário sobre scripts de shell lol.
quickshiftin

3
Esta solução não funciona em um .shscript ao tentar atribuir o caractere recuperado a uma variável. Por exemplo, declare LAST=$(echo "${str: -1}") isso resultará na barra vermelha desagradável, mostrando um erro de sintaxe iniciando no:
krb686

3
Se a verificação de sintaxe editor não gosta que o espaço tentativa${str:0-1}
ttt

36

Eu sei que esse é um tópico muito antigo, mas ninguém mencionou qual é a resposta mais limpa para mim:

echo -n $str | tail -c 1

Observe que isso -né apenas para que o eco não inclua uma nova linha no final.


15
Nem mesmo perto de ser mais limpo do que $ {str: -1}
shrewmouse

8
É mais limpo, pois não depende de um bash-ism, por isso funcionará com qualquer shell Posix.
John Eikenberry

Qual é o mais "bashist"? "$ {str: -1}" E ... Qual é o mais limpo? "$ {str: -1}" Bash é o besht! :-)
Roger

Para quem tenta imprimir os últimos caracteres em um arquivo grande, isso fez o trabalho para mim: cat user / folder / file.json | tail -c 1 Você pode substituir o 1 pelo número de caracteres que deseja imprimir.
Diego Serrano

5

outra solução usando o script awk:

último 1 caractere:

echo $str | awk '{print substr($0,length,1)}'

últimos 5 caracteres:

echo $str | awk '{print substr($0,length-5,5)}'

1
Não é o que o OP pediu, mas esta é a melhor solução que encontrei para ser usada com um arquivo. A maioria das outras abordagens não funciona como um arquivo para ele, como em: cat file | awk '{print substr($0,length,1)}'Obrigado!
X28 de

4

Única linha:

${str:${#str}-1:1}

Agora:

echo "${str:${#str}-1:1}"

1
Por que você usa dois pares de parênteses? Além disso, desde o 4.2, você pode usar compensações negativas, conforme mostrado na resposta do quickshiftin: echo "${str: -1}"é suficiente (lembre-se do espaço entre :e -).
gniourf_gniourf

Dois pares de parênteses são usados para operações aritméticas
Eduardo Cuomo

Não. Consulte a parte relevante do manual onde você lerá: comprimento e deslocamento são expressões aritméticas (consulte Aritmética do Shell ); portanto, você já está com aritmética de casca e não precisa de nenhum parêntese. Além disso, se o que você disse fosse verdade, seria mais lógico ter uma expansão aritmética com $((...)).
gniourf_gniourf

@gniourf_gniourf você está certo! Agora eu entendo sua pergunta anterior. Resposta atualizada
Eduardo Cuomo

4

Até agora, todas as respostas implicam que a palavra "shell" na pergunta equivale a Bash.

É assim que se pode fazer isso em um shell Bourne padrão:

printf $str | tail -c 1

1
echo -nconforme proposto por user5394399 evita problemas quando $strcontém caracteres de formato especial.
Conrad Meyer

A -nmudança é um basismo. Não funcionará no shell Bourne padrão como traço, etc ... Qual foi o ponto da minha resposta.
Phep # 25/18

1
Não é um basismo, mas o POSIX reconhece que sua implementação está definida ("Se o primeiro operando for -n, ou se algum dos operandos contiver um caractere <slash>, os resultados serão definidos pela implementação"). Sua resposta pode ser corrigida com printf "%s" "$str" | ...:-).
Conrad Meyer

4

Experimentar:

"${str:$((${#str}-1)):1}"

Por exemplo:

someone@mypc:~$ str="A random string*"; echo "$str"
A random string*
someone@mypc:~$ echo "${str:$((${#str}-1)):1}"
*
someone@mypc:~$ echo "${str:$((${#str}-2)):1}"
g

-2
echo $str | cut -c $((${#str}))

é uma boa abordagem

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.