Usando la salida de la expresión en el corte de cadenas de bash

Usando la salida de la expresión en el corte de cadenas de bash

Quiero extraer una subcadena de un nombre de archivo de una ruta de longitud desconocida. Puedo hacer estas dos partes por separado, pero me pregunto si hay alguna manera de combinar las dos sin una variable temporal.

INPUT_PATH=/path/to/subfolder/file_17.txt 
# I would like to extract "17", the filname will always be 'file_XX.txt'
# The subfolder name is variable length 

TMP=$(basename ${INPUT_PATH})
FILE_NUMBER=${TMP:5:2}
echo ${FILE_NUMBER} # This works as expected

Lo intenté ${$(basename $INPUT_PATH):5:2}pero me da un error de sustitución grave. ¿Hay algún truco para hacer esto?

Respuesta1

Adoptar un enfoque diferente al problema y proporcionar una solución unificada utilizando únicamente bashla funcionalidad:

$ cat demo.sh
#!/bin/bash

INPUT_PATH=/path/to/subfolder/file_17.txt

FILE_NUMBER=${INPUT_PATH:((${#INPUT_PATH} -6)):2}
echo ${FILE_NUMBER}
$

$./demo.sh
17

Un método más sencillo sería contar hacia atrás desde el final de la cadena, es decir

FILE_NUMBER=${INPUT_PATH: -6:2}

Obviamente, esta solución depende de la variable de cadena que termina en "##XXXX", donde "##" son los dos dígitos de interés y "XXXX" son los últimos 4 caracteres de la cadena.

Respuesta2

Como estás usando bash, puedes usar la coincidencia de expresiones regulares:

if [[ $input =~ ([[:digit:]]+)\.txt$ ]]; then
    file_num=${BASH_REMATCH[1]}
fi

Respuesta3

La forma más sencilla es utilizar FILE_NUMBER en lugar de TMP:

FILE_NUMBER=$(basename ${INPUT_PATH})
FILE_NUMBER=${FILE_NUMBER:5:2}

Además, usar la expansión de parámetros es más rápido que llamar al nombre base:

FILE_NUMBER=${INPUT_PATH##*/}
FILE_NUMBER=${FILE_NUMBER:5:2}

Puedes usar sed para hacer todo en una sola línea, pero es más lento y menos legible:

FILE_NUMBER=$(sed 's|.*/||;s/.....\(..\).*/\1/' <<<"$INPUT_PATH")

Respuesta4

Para aquellos que usan zshen lugar de bash:

  • 6to a 7mo personajes delcola(parte devuelta por basename) de una ruta:

    num=${${a_path:t}[6,7]}
    

    ( $var:tde cshpara conseguir el ttodo)

    También puede num=${"$(basename -- "$a_path")":5:2}utilizar ese ksh93 ${var:offset:length}operador agregado recientemente zshpara mayor compatibilidad. La sustitución del comando debe estar entre comillas para que no genere una matriz, de modo que seleccione :5:2un rango de caracteres en lugar de un rango de elementos de la matriz. Sin embargo, usar la sustitución y ejecución de comandos basenameterminaría siendo menos eficiente y menos confiable que usar zshel :toperador incorporado.

  • primera secuencia de dígitos en elcola:

    num=${(MS)${a_path:t}##<->}
    

    ${var##pattern}es el operador ksh que elimina la cadena inicial más larga que coincide con patternfrom $var. Con la Mbandera, la Mparte adjunta se devuelve en lugar de eliminarse y Sbusca Scadenas secundarias, no solo al principio. Y <->coincide con cualquier secuencia de dígitos ( <x-y>con límites no especificados).

  • secuencia de dígitos después de a _en elcola:

    num=${${a_path:t}/(#m)*_(<->)*/$match[1]}
    

    (necesita extendedglob; tenga cuidado, devuelve la cola completa si no hay _digitsin $a_path).

    O:

    [[ $a_path:t =~ '_([[:digit:]]+)' ]] && num=$match[1]
    

información relacionada