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.