Como obter o char em uma determinada posição de uma string no shell script?

21

Como obter o char em uma determinada posição de uma string no shell script?

Tom Brito
fonte

Respostas:

35

No bash com "Parameter Expansion" $ {parameter: offset: length}

$ var=abcdef
$ echo ${var:0:1}
a
$ echo ${var:3:1}
d

Edit: Sem expansão de parâmetros (não muito elegante, mas foi o que me ocorreu primeiro)

$ charpos() { pos=$1;shift; echo "$@"|sed 's/^.\{'$pos'\}\(.\).*$/\1/';}
$ charpos 8 what ever here
r
forcefsck
fonte
1
gnu.org/software/bash/manual/... tem mais detalhes
jsbillings
Aparentemente, não é POSIX: pubs.opengroup.org/onlinepubs/009695399/utilities/…
Ciro Santilli foi membro da equipe de Ciro Santilli em
Você também pode definir o offset 'de ponta' como assimecho ${var: -2:1}
Vassilis
Essa sintaxe vem do ksh93 e também é suportada por zshe mksh.
Stéphane Chazelas
6

A alternativa à expansão de parâmetros é expr substr

substr STRING POS LENGTH
    substring of STRING, POS counted from 1

Por exemplo:

$ expr substr hello 2 1
e
dogbane
fonte
legal, deveria ter verificado a expr mais minuciosamente.
forcefsck
1
Embora isso pareça funcionar com o expr do GNU coreutils, substrnão está incluído no expr do FreeBSD, NetBSD ou OS X. Esta não é uma solução portátil.
ghoti
@ ghoti, observe que substrnão é originalmente uma extensão GNU. A implementação original exprveio do PWB Unix no final dos anos 70 e teve substr(mas não :).
Stéphane Chazelas
@ StéphaneChazelas, obrigado por adicionar uma perspectiva histórica. :) Embora eu tenha certeza de que o uso do PWB não é relevante para o OP, é sempre divertido rastrear recursos e alterações ao longo das décadas. O GNU tende a ser o padrão de muitas pessoas, mas, em geral, acho que evitaria o uso de opções que não são claramente POSIX e são conhecidas como ausentes nos principais departamentos.
ghoti 6/09
5

cut -c

Se a variável não contiver novas linhas, você poderá:

myvar='abc'
printf '%s\n' "$myvar" | cut -c2

saídas:

b

awk substr é outra alternativa POSIX que funciona mesmo que a variável tenha novas linhas:

myvar="$(printf 'a\nb\n')" # note that the last newline is stripped by
                           # the command substitution
awk -- 'BEGIN {print substr (ARGV[1], 3, 1)}' "$myvar"

saídas:

b

printf '%s\n'é evitar problemas com caracteres de escape: /programming//a/40423558/895245, por exemplo:

myvar='\n'
printf '%s\n' "$myvar" | cut -c1

saídas \conforme o esperado.

Consulte também: /programming/1405611/extracting-first-two-characters-of-a-string-shell-scripting

Testado no Ubuntu 19.04.

Ciro Santilli adicionou uma nova foto
fonte
printf '%s' "$myvar" | cut -c2não é POSIX, pois a saída de printfnão é texto, a menos que $myvartermine com um caractere de nova linha. Caso contrário, assume que a variável não contém caracteres de nova linha como cutcorta cada linha de sua entrada.
Stéphane Chazelas
O awkprimeiro seria mais eficiente e confiável comawk -- 'BEGIN {print substr (ARGV[1], 2, 1)}' "$myvar"
Stéphane Chazelas
Observe que nas versões atuais do GNU cut, isso não funciona para caracteres de vários bytes (o mesmo para mawk ou busybox awk)
Stéphane Chazelas
@ StéphaneChazelas obrigado pelos pontos. Não entendi o que você quis dizer no primeiro: você quer dizer que printf 'abc '| cut -c2está errado porque não \n(não sei disso) ou que o comando falhará se myvar tiver novas linhas (concordo)?
Ciro Santilli sexta-feira,
1
O comportamento de cutnão é especificado se a entrada não for texto (embora cutsejam necessárias implementações para manipular linhas ou comprimento arbitrário). A saída de printf abcnão é texto , pois não termina em um caractere de nova linha. Na prática, dependendo da implementação, se você canalizar isso para cut -c2você obter qualquer b, b<newline>ou nada. Você precisaria printf 'abc\n' | cut -c2obter um comportamento especificado pelo POSIX (que é necessário para a saída b<newline>)
Stéphane Chazelas
1

Com zshou yash, você usaria:

$ text='€$*₭£'
$ printf '%s\n' "${text[3]}"
*

(em zsh, você pode abreviá-lo printf '%s\n' $text[3]).

Stéphane Chazelas
fonte
0

Você pode usar o comando recortar. Para obter a terceira posição:

echo "SAMPLETEXT" | cut -c3

Verifique este link http://www.folkstalk.com/2012/02/cut-command-in-unix-linux-examples.html

( Casos avançados ) No entanto, modificar o IFS também é uma coisa boa, especialmente quando sua entrada pode ter espaços. Somente nesse caso, use o abaixo

saveifs=$IFS
IFS=$(echo -en "\n\b")
echo "SAMPLETEXT" | cut -c3
IFS=$saveifs
Midhun Jose
fonte
Não vejo como IFSentraria em jogo no código que você postou.
Kusalananda