¿Cómo obtener el carácter en una posición dada de una cadena en el script de shell?

22

¿Cómo obtener el carácter en una posición dada de una cadena en el script de shell?

Tom Brito
fuente

Respuestas:

36

En bash con "Expansión de parámetros" $ {parámetro: desplazamiento: longitud}

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

Editar: Sin expansión de parámetros (no muy elegante, pero eso fue lo primero que me vino)

$ charpos() { pos=$1;shift; echo "$@"|sed 's/^.\{'$pos'\}\(.\).*$/\1/';}
$ charpos 8 what ever here
r
forcefsck
fuente
1
gnu.org/software/bash/manual/... tiene más detalles
jsbillings
Aparentemente no POSIX: pubs.opengroup.org/onlinepubs/009695399/utilities/…
Ciro Santilli 新疆 改造 中心 法轮功 六四 事件
También puede establecer el desplazamiento 'desde el final' de esta maneraecho ${var: -2:1}
Vassilis
Esa sintaxis proviene de ksh93 y también es compatible con zshy mksh.
Stéphane Chazelas
6

La alternativa a la expansión de parámetros es expr substr

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

Por ejemplo:

$ expr substr hello 2 1
e
dogbane
fuente
genial, debería haber comprobado expr más a fondo.
forcefsck
1
Si bien esto parece funcionar con el expr de GNU coreutils, substrno está incluido en el expr de FreeBSD, NetBSD u OS X. Esta no es una solución portátil.
ghoti
@ ghoti, tenga en cuenta que substroriginalmente no es una extensión GNU. La implementación original exprde PWB Unix vino a finales de los 70 y tenía substr(pero no :).
Stéphane Chazelas
@ StéphaneChazelas, gracias por agregar una perspectiva histórica. :) Si bien estoy bastante seguro de que el uso de PWB no es relevante para el OP, siempre es divertido rastrear características y cambios a lo largo de las décadas. GNU tiende a ser el valor predeterminado de muchas personas, pero en general, creo que evitaría usar opciones que no sean claramente POSIX , y que se sabe que faltan en los principales unices.
ghoti
5

cut -c

Si la variable no contiene nuevas líneas, puede hacer:

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

salidas:

b

awk substr es otra alternativa POSIX que funciona incluso si la variable tiene nuevas líneas:

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"

salidas:

b

printf '%s\n'es para evitar problemas con los caracteres de escape: /programming//a/40423558/895245 por ejemplo:

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

salidas \como se esperaba.

Ver también: /programming/1405611/extracting-first-two-characters-of-a-string-shell-scripting

Probado en Ubuntu 19.04.

Ciro Santilli 新疆 改造 中心 法轮功 六四 事件
fuente
printf '%s' "$myvar" | cut -c2no es POSIX ya que la salida de printfno es texto a menos que $myvartermine en un carácter de nueva línea. De lo contrario, se supone que la variable no contiene caracteres de nueva línea, ya que cutcorta cada línea de su entrada.
Stéphane Chazelas
El awkuno sería más eficiente y confiable conawk -- 'BEGIN {print substr (ARGV[1], 2, 1)}' "$myvar"
Stéphane Chazelas el
Tenga en cuenta que con las versiones actuales de GNU cut, eso no funciona para caracteres de varios bytes (lo mismo para mawk u busybox awk)
Stéphane Chazelas
@ StéphaneChazelas gracias por los puntos. No entendí lo que quieres decir en el primero: ¿quieres decir que printf 'abc '| cut -c2está mal porque no \n(esto no lo sé) o que el comando fallará si myvar tiene líneas nuevas (estoy de acuerdo)?
Ciro Santilli 新疆 改造 中心 法轮功 六四 事件
1
El comportamiento de cutno se especifica si la entrada no es texto (aunque cutse requieren implementaciones para manejar líneas o longitud arbitraria). La salida de printf abcno es texto, ya que no termina en un carácter de nueva línea. En la práctica, dependiendo de la aplicación, si la tubería que a cut -c2, se obtiene ya sea b, b<newline>o nada en absoluto. Necesitaría printf 'abc\n' | cut -c2obtener un comportamiento especificado por POSIX (que se requiere para la salida b<newline>)
Stéphane Chazelas
1

Con zsho yash, usarías:

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

(en zsh, puedes acortarlo a printf '%s\n' $text[3]).

Stéphane Chazelas
fuente
0

Puedes usar el comando de corte. Para obtener la tercera posición:

echo "SAMPLETEXT" | cut -c3

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

( Casos avanzados ) Sin embargo, modificar IFS también es algo bueno, especialmente cuando su entrada puede tener espacios. Solo en ese caso, use el siguiente

saveifs=$IFS
IFS=$(echo -en "\n\b")
echo "SAMPLETEXT" | cut -c3
IFS=$saveifs
Midhun Jose
fuente
No puedo ver cómo IFSentraría en juego el código que publicaste.
Kusalananda