Indexar una cadena en bash


14

¿Cómo puedo referirme a una cadena por índice en sh / bash? Es decir, básicamente dividiéndolo.

Estoy tratando de quitar 5 caracteres de un nombre de archivo. Todos los nombres tienen la estructura: nombre_nr_código. Estoy tratando de eliminar el bit de código 5 alfanumérico. name_nr_Siempre tiene 10 caracteres.

¿Hay algo así como;

for i in * ; do mv "$i" "$i"[:10] ; done


55
¿Por qué la bashetiqueta si estás pidiendo una shsolución?
Stéphane Chazelas

Respuestas:


14

Tan simple como esto.

(golpetazo)

for i in * ; do mv -- "$i" "${i:0:5}" ; done

Voila

Y una explicación de Advanced Bash-Scripting Guide ( Capítulo 10. Manipulación de variables ) , (con NOTEs adicional en línea para resaltar los errores en ese manual):

Extracción de subcadena

${string:position}

Extrae la subcadena de $stringat $position.

Si el $stringparámetro es "*" o "@", esto extrae los parámetros posicionales, comenzando en $position.

${string:position:length}

Extrae $lengthcaracteres de la subcadena de $stringat $position.

NOTEfaltan comillas alrededor de expansiones de parámetros! echono debe usarse para datos arbitrarios.

stringZ=abcABC123ABCabc
#       0123456789.....
#       0-based indexing.

echo ${stringZ:0}                       # abcABC123ABCabc
echo ${stringZ:1}                       # bcABC123ABCabc
echo ${stringZ:7}                       # 23ABCabc 

echo ${stringZ:7:3}                     # 23A
                                        # Three characters of substring.


# Is it possible to index from the right end of the string?

echo ${stringZ:-4}                      # abcABC123ABCabc
# Defaults to full string, as in ${parameter:-default}.
# However . . . 

echo ${stringZ:(-4)}                    # Cabc
echo ${stringZ: -4}                     # Cabc
# Now, it works.
# Parentheses or added space "escape" the position parameter.

Los argumentos de posición y longitud pueden "parametrizarse", es decir, representarse como una variable, en lugar de como una constante numérica.


Si el $stringparámetro es "*" o "@", esto extrae un máximo de $lengthparámetros posicionales, comenzando en $position.

echo ${*:2}          # Echoes second and following positional parameters.
echo ${@:2}          # Same as above.

echo ${*:2:3}        # Echoes three positional parameters, starting at second.

NOTE: expr substres una extensión de GNU.

expr substr $string $position $length

Extrae $lengthpersonajes desde el $stringcomienzo $position.

stringZ=abcABC123ABCabc
#       123456789......
#       1-based indexing.

echo `expr substr $stringZ 1 2`           # ab
echo `expr substr $stringZ 4 3`           # ABC

NOTE: Eso echoes redundante y lo hace aún menos confiable. Uso expr substr + "$string1" 1 2.

NOTE: exprvolverá con un estado de salida distinto de cero si la salida es 0 (o -0, 00 ...).


Por cierto. El libro está presente en el repositorio oficial de Ubuntu como abs-guide.


Decir "posición" es un poco engañoso, ya que en realidad es un desplazamiento, lo que significa que ${var:1}no devuelve el valor de vardesde la "primera posición", sino de la segunda.
Kusalananda

Eso es cierto, pero mientras no esté de acuerdo, puede haber una posición cero. Lo cual está bien conmigo.

9

En POSIX sh,

  • "${var%?????}"está $vardespojado de los últimos 5 caracteres finales (o $varsi $varcontiene menos de 5 caracteres)

  • "${var%"${var#??????????}"}"es los primeros 10 caracteres de $var.

  • "${var%_*}"se $vardespoja de la cadena más corta que coincide _*al final de $var( foo_bar_baz-> foo_bar).
  • "${var%%_*}": coincidencia igual pero más larga en lugar de la coincidencia más corta ( foo_bar_baz-> foo).
  • si desea obtener foo_bar_: "${var%"${var##*_}"}"( ${var##pattern}es lo mismo que ${var%%pattern}buscar el patrón al principio y $varno al final).

Con zsh:

  • $var[1,-6] desde el primer personaje hasta el sexto desde el final (así que todos menos los últimos 5).
  • $var[1,10] para los primeros 10 caracteres.

Con ksh, basho zsh:

  • "${var:0:10}": primeros 10 caracteres de $var

Con basho zsh:

  • "${var:0:-5}": todos menos los últimos 5 caracteres (da un error y sale del script si $varestá configurado pero contiene menos de 5 caracteres, también cuando $varno está configurado con zsh).

Si necesita shcompatibilidad con Bourne , es muy difícil hacerlo de manera confiable. Si puede garantizar que el resultado no terminará en caracteres de nueva línea, puede hacer:

first_10=`expr " $var" : ' \(.{1,10\}\)'` # beware the exit status
                                          # may be non-zero if the
                                          # result is 0 or 0000000000

all_but_last_5=`expr " $var" : ' \(.*\).\{5\}'`

También tendrá un límite en la longitud de $var(que varía entre sistemas).

En todas esas soluciones, si $varcontiene bytes que no pueden formar parte de caracteres válidos, YMMV.


mi, realmente se les ocurrió una sintaxis fea para dentro de esos aparatos.
gato

2

shno proporciona una forma integrada de obtener una subcadena de una cadena (por lo que puedo ver), pero con bashusted puede hacer

${i:0:10}

Esto le dará los primeros diez caracteres del valor de la variable i.

El formato general es ${variable:offset:length}.


2

La mayoría de los shells admiten algún tipo de expansión de parámetros que pueden ayudarlo. En bash, puedes usar

substr=${string:4:5} # start at position 4, length 5.

En dash, las compensaciones no son compatibles, pero puede usar patrones iniciales y finales:

remove_first3=${string#???}
remove_last2=${string%??}

0

En primer lugar, no use un forbucle para los nombres de archivo.

Entonces, algo como esto debería ayudar.

find ./ -type f | while read filename ;do
  newfilename=$(echo ${filename}|cut -c 1-10)
  mv ${filename} ${newfilename}
done

3
¿Por qué es malo usar forcon nombres de archivo?
choroba

Cita tus variables y solía printfser más seguro. ... y read -r.
Kusalananda

3
El forbucle del OP estaba bien, excepto tal vez por los desaparecidos --. ¡Puedo ver al menos 10 errores en tus 4 líneas de código! muchas de las cuales son malas prácticas bien conocidas, como suponer que los nombres de los archivos son de una sola línea, usan eco, faltan comillas
Stéphane Chazelas
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.