¿Cómo dividir el nombre del archivo en variable?


11

Supongamos que tengo una lista de archivos csv con el siguiente formato:

INT_V1_<Product>_<ID>_<Name>_<ddmmyy>.csv
ASG_B1_V1_<Product>_<ID>_<Name>_<ddmmyy>.csv

El INT_V1_ y ASG_B1_V1_ es fijo, lo que significa que todos los archivos csv comienzan con él.
¿Cómo puedo dividir los nombres de archivo en variable?
Por ejemplo, quería capturar el Nombre y asignarlo a una variable $Name.


¿Por qué la etiqueta "bash", si está utilizando ksh en AIX 7.1?
— Stéphane Chazelas

Deseo producir un script bash. Solo que quería probarlo primero en ksh, perdón por causarte problemas.
— Juliet.Y

Respuestas:


7

Con zsh:

file='INT_V1_<Product>_<ID>_<Name>_<ddmmyy>.csv'

setopt extendedglob
if [[ $file = (#b)*_(*)_(*)_(*)_(*).csv ]]; then
  product=$match[1] id=$match[2] name=$match[3] date=$match[4]
fi

Con bash4.3 o más reciente, ksh93t o más nuevo o zsh en emulación sh (aunque en zsh, preferiría simplemente field=("${(@s:_:)field}")dividir en lugar de usar el operador sin sentido split + glob de sh) podría dividir la cadena en los _caracteres y hacer referencia a ellos desde el final :

IFS=_
set -o noglob
field=($file) # split+glob  operator
date=${field[-1]%.*}
name=${field[-2]}
id=${field[-3]}
product=${field[-4]}

O (bash 3.2 o más reciente):

if [[ $file =~ .*_(.*)_(.*)_(.*)_(.*)\.csv$ ]]; then
  product=${BASH_REMATCH[1]}
  id=${BASH_REMATCH[2]}
  name=${BASH_REMATCH[3]}
  date=${BASH_REMATCH[4]}
fi

(se supone que $filecontiene texto válido en la configuración regional actual que no está garantizado para los nombres de archivo a menos que arregle la configuración regional en C u otra configuración regional con un solo byte por juego de caracteres).

Como zshel de *arriba, .*es codicioso . Entonces, el primero comerá la mayor cantidad *_posible, por lo que el resto .*solo coincidirá con _cadenas libres.

Con ksh93, podrías hacer

pattern='*_(*)_(*)_(*)_(*).csv'
product=${file//$pattern/\1}
id=${file//$pattern/\2}
name=${file//$pattern/\3}
date=${file//$pattern/\4}

En un POSIX shscript, podría utilizar los ${var#pattern}, ${var%pattern}operadores de expansión de parámetros estándar:

rest=${file%.*} # remove .csv suffix
date=${rest##*_} # remove everything on the left up to the rightmost _
rest=${rest%_*} # remove one _* from the right
name=${rest##*_}
rest=${rest%_*}
id=${rest##*_}
rest=${rest%_*}
product=${rest##*_}

O use el operador split + glob nuevamente:

IFS=_
set -o noglob
set -- $file
shift "$(($# - 4))"
product=$1 id=$2 name=$3 date=${4%.*}

Estoy usando bash en AIX7.1 y actualmente estoy probando en ksh. De alguna manera me encuentro con un error que indica ksh: file: 0403-046 The specified subscript cannot be greater than 4095.para ${field[-1]}o cualquier cosa en forma ${x[n]}.
— Juliet.Y

@Juliet, ${field[-1]}era para bash-4.3+. Para ksh, utilice cualquiera de las soluciones "POSIX". La compatibilidad con el subíndice negativo no se agregó antes de ksh93t (una característica que se origina en zsh).
— Stéphane Chazelas

Ok, notado. Muchas gracias, los scripts están funcionando bien.
— Juliet.Y

4

Puede tomar los valores de su campo <Name>con este comando:

cut -d'<' -f4 < csvlist | sed -e 's/>_//g'

(o con awk):

awk -F'<' '{print $4}' < csvlist | sed -e 's/>_//g'

Y puedes ponerlos en una variable como esta:

variable_name=$(cut -d'<' -f4 < csvlist | sed -e 's/>_//g')

o

awk -F'<' '{print $4}' < csvlist | sed -e 's/>_//g'

No está claro en la pregunta si desea la misma variable para todos los valores o una sola variable para cada uno de ellos.


1
file='INT_V1_<Product>_<ID>_<Name>_<ddmmyy>.csv'
IFS=\_ read -r x x product id name date x <<< "$file"
date=${date%.*}

Tenga en cuenta que _no es especial y no necesita ser citado. Eso supone que el nombre del archivo no contiene caracteres de nueva línea. Es posible que desee agregar a -d ''.
— 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.