Comment diviser un nom de fichier en variable?


11

Supposons que j'ai une liste de fichiers csv au format suivant:

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

Le INT_V1_ & ASG_B1_V1_ est fixe, ce qui signifie tous les fichiers csv commencent avec elle.
Comment puis-je diviser les noms de fichiers en variables?
Par exemple, je voulais capturer le nom et l'attribuer à une variable $Name.


Pourquoi la balise "bash", si vous utilisez ksh sur AIX 7.1?
— Stéphane Chazelas

Je souhaite produire un script bash. Juste que je voulais l'essayer d'abord sur ksh, désolé de vous avoir causé des ennuis.
— Juliet.Y

Réponses:


7

Avec 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

Avec bash4.3 ou plus récent, ksh93t ou plus récent ou zsh dans l'émulation sh (bien que dans zsh, vous préférez tout simplement faire field=("${(@s:_:)field}")pour le fractionnement plutôt que d'utiliser l'opérateur de non-sens split + glob de sh), vous pouvez diviser la chaîne en _caractères et les référencer depuis la fin :

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

Ou (bash 3.2 ou plus récent):

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

(cela suppose qu'il $filecontient du texte valide dans les paramètres régionaux actuels, ce qui n'est pas garanti pour les noms de fichiers, sauf si vous fixez les paramètres régionaux à C ou à d'autres paramètres régionaux avec un seul octet par jeu de caractères).

Comme zsh« est *ci - dessus, l' .*est avide . Ainsi, le premier en mangera autant *_que possible, de sorte que le reste .*ne correspondra qu'à des _chaînes libres.

Avec ksh93, tu pourrais faire

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

Dans un POSIX shscript, vous pouvez utiliser les ${var#pattern}, ${var%pattern}opérateurs d'extension de paramètres standard:

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##*_}

Ou utilisez à nouveau l'opérateur split + glob:

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

J'utilise bash sur AIX7.1 et je teste actuellement dans ksh. D'une certaine manière je rencontre une erreur indiquant ksh: file: 0403-046 The specified subscript cannot be greater than 4095.pour ${field[-1]}ou quoi que ce soit sous forme ${x[n]}.
— Juliet.Y

@Juliet, ${field[-1]}c'était pour bash-4.3+. Pour ksh, utilisez l'une des solutions "POSIX". La prise en charge de l'indice négatif n'a pas été ajoutée avant ksh93t (une fonctionnalité originaire de zsh).
— Stéphane Chazelas

OK, c'est noté. Merci beaucoup, les scripts fonctionnent bien.
— Juliet.Y

4

Vous pouvez prendre les valeurs de votre champ <Name>avec cette commande:

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

(ou avec awk):

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

Et vous pouvez les mettre dans une variable comme celle-ci:

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

ou

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

Il n'est pas clair dans la question si vous voulez la même variable pour toutes les valeurs ou une seule variable pour chacune d'elles.


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

Notez que ce _n'est pas spécial et n'a pas besoin d'être cité. Cela suppose que le nom de fichier ne contient pas de caractères de nouvelle ligne. Vous voudrez peut-être ajouter un -d ''.
— Stéphane Chazelas
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.