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?

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



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

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.


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]).


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

Não vejo como IFSentraria em jogo no código que você postou.
Kusalananda
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.