Script bash : délimiter un nom de fichier

Bonjour à tous,

J’ai beaucoup cherché sur le net mais je n’ai pas trouvé comment résoudre mon problème.
Je travaille dans une entreprise où je dois maintenir en fonctionnement tout un tas de serveurs.
Régulièrement j’ai donc pas mal de commandes à faire.
J’ai commencé à en automatiser beaucoup, par le biais de scripts en bash, mais là je sèche.

Dans un dossier backup où chaque jour un backup est fait, je dois déplacer les dossiers vieux de + de 3 mois, des 10ème, 20ème et 30ème jour du mois, appelés nas_back_130701, nas_back_130702 etc etc

En commande, je fais tout simplement :
mv nas_back_130410/ nas_back_2013/.
mv nas_back_130420/ nas_back_2013/.
mv nas_back_130430/ nas_back_2013/.
rm nas_back_1304* -rf

Je pensais isoler les dossiers en fonction de leur nom :
ls -lrth | awk -F_ ’ {print$3}'
mais je n’arrive pas à délimiter la fin du nom du fichier “130410”, pour extraire l’année, le mois et le jour et le comparer à la date réelle, afin de déplacer et supprimer ceux qui m’intéressent.

Est-ce que quelqu’un peut m’aider ? Est-ce que je suis sur la bonne voie ?

Merci d’avance !!

Je bascule ton fil chez les codeurs.

find ./ -maxdepth 1 -type d -iregex ".*nas_back_[0-9_]+$" | sed 's/.\/nas_back_//'

où dans l’ordre :

find ./ -maxdepth 1 -type d -iregex ".*nas_back_[0-9_]+$" | sed 's/.\/nas_back_//' | sort

Un début:

[code]#!/bin/sh

ls | while read l; do
yymmdd="${l##*_}“
yy=”${yymmdd%???}"; mmdd="${yymmdd#??}“
mm=”${mmdd%??}"; dd="${mmdd#??}"
echo "20$yy $yy $mm $dd"
done[/code]

Merci à tous les deux pour vos réponses.
Je préfère la solution de tukuyomi, qui décompose le nom de fichier plus précisément.
Ca marche nickel, super :slightly_smiling:

Est-ce que tu peux me dire à quoi correspond #, ? et % ?
Comment on s’en sert ?

[quote=“igorb”]

Est-ce que tu peux me dire à quoi correspond #, ? et % ?
Comment on s’en sert ?[/quote]

man bash à lire tranquillement, on y découvre des choses comme celles-là. C’est en français, et je l’ai imprimé ( pardon, la forêt ) et le relit peut-être une fois par an.

sinon: man bash puis '/${' , ou autre commande de recherche de ton lecteur de man sur la chaine: ${

en attendant:

[code]nouveau=${nom%suf} le suffixe est supprimé
nouveau=${nom#pref} le préfixe est supprimé

si % ou # sont doublés ( %% ou ## ) la partie supprimée est la plus longue ( chaine répétée )

? et * sous bash tu ne connais pas ? :wink:
? un caractère quelconque

  • de zéro à plusieurs caractères quelconques

[/code]

Je m’étais fait une petite synthèse il y a déjà pas mal de temps: ici http://joseph-tux.legrillon.info/Operateur-variable?lang=fr, le paragraphe “EXTRACTION” répond aussi à ta question.

Dans ce genre de cas, j’utilise la commande cut. Cela évite de dépendre de bash, car un système peut utiliser un autre shell.
Par exemple (avec un echo mais ça marche avec ls et autres…) :

echo "nas_back_130410" | cut -d'_' -f3- 130410

Voir le manuel pour bien comprendre là aussi

Bonjour,

C’est une autre façon de voir la chose mais si je comprend bien, tu ne gardes que les fichiers qui se finissent par un “0”. Du coup, moi je ferais un truc comme :

#!/bin/bash

for i in `ls backup/`
do

if echo $i |grep "0$"
then
 mv backup/$i back2013
else
 rm -Rf backup/$i
fi

done
* plusieurs caractères quelconques

je préfère “de 0 à une infinité de caractères quelconques”

Perso je pense que je ferrais ça :

dossier="$1" # là où se trouvent tout tes dossiers à traiter marqueur=$(date -d '-4 months' '+nas_back_%y%m') for fichier in "${dossier}/"* ; do [[ "${fichier}" > "${dossier}/${marqueur}" ]] && break # blabla done
[ul]
[li]gestion des dates fiables (en janvier c’est quel mois 4 moi avant ?)[/li]
[li]on est relativement peu dépendant du format des noms de fichiers (il faut juste bien faire gaffe au format que l’on donne à la commande date)[/li][/ul]

[quote=“nilux17”]

* plusieurs caractères quelconques

je préfère “de 0 à une infinité de caractères quelconques”[/quote]

100 fois oui, tu as raison, je rectifie ( hier j’étais vraiment très pressé )

[quote=“nilux17”][code]
#!/bin/bash

for i in ls backup/
do

if echo $i |grep "0$"
then
mv backup/$i back2013
else
rm -Rf backup/$i
fi

done

[/code][/quote]
J’aime beaucoup la confiture :

#!/bin/bash

for i in backup/*
do
    if [[ "$i" =~ 0$ ]]
    then
        mv "$i" back2013
    else
        rm -Rf "$i"
    fi
done

[quote=“josephtux”][quote=“nilux17”]

* plusieurs caractères quelconques

je préfère “de 0 à une infinité de caractères quelconques”[/quote]

100 fois oui, tu as raison, je rectifie ( hier j’étais vraiment très pressé )[/quote]
Je préfère (même si c’est moins clair, mais ça permet de voir le goinfre que c’est) :
Éventuellement, le maximum de caractères quelconques.

Et avec Perl (substr):

où $n est le nom du fichier et $d les 6 derniers caractères (la date)

Pour détailler la date en N° du jour, du mois, de l’ année:

Ce qui donne un début de code: ( remplacer echo comparer par la condition en utilisant $i, et déplacer nas_$i ):

qui affiche:
[size=90]comparer 130410 130706
comparer 130420 130706
comparer 130430 130706
comparer 130510 130706[/size]

Voilà comment je ferais pour récupérer les fichiers à archiver :

find <dossier_sauvegarde> -type f -maxdepth 1 \( ! -cnewer <dossier_sauvegarde>/nas_back_$(date -d '-3 months -1 day' -name 'nas_back_*' \) -o -name 'nas_back_*[123]0'

Pour déterminer le dossier cible, il faut une précision :
le “2013” de ton exemple correspond t’il à l’année courante où à l’année du fichier ?

merci à tous pour vos réponses.
je rentre de vacances, j’ai du boulot, je vais essayer tout ça

[quote=“josephtux”]Et avec Perl (substr):

où $n est le nom du fichier et $d les 6 derniers caractères (la date)

Pour détailler la date en N° du jour, du mois, de l’ année:

Ce qui donne un début de code: ( remplacer echo comparer par la condition en utilisant $i, et déplacer nas_$i ):

qui affiche:
[size=90]comparer 130410 130706
comparer 130420 130706
comparer 130430 130706
comparer 130510 130706[/size]
[/quote]

Je suis en train de regarder ton code, sachant que je n’y connais rien à Perl.
Comment modifier ton code pour que le nom du fichier s’affiche sans le dernier caractère qui est une virgule :
ls -1 nas* | perl -lane '$n=$F[0];
Pour que je puisse traiter les fichiers ensuite, la virgule me gêne :confused:

merci

Voilà au final le script que j’ai fait.
Je le poste au cas où quelqu’un serait intéressé.
J’imagine qu’il doit y avoir plus simple, ou plus propre, mais ca marche.

[code]#!/bin/bash

VARIABLES

mois_precedent=$(date --date=‘1 months ago’ +%b)
mois_fevrier=‘févr.’

FILTRAGE DES RESULTATS EN EXCLUANT LES DOSSIERS ANNUELS ET LEUR CONTENU

AVEC DELAI DE 30 JOURS

i=0
find /var/dumps/ -type d ! -name “nas_back_2012” ! ( -name “nas_back_2013” -prune ) -mtime +30 -ls | while read line ; do

    i=$((x+1))

EXTRACTION DES CHAMPS JOURS ET MOIS

    jour_nasback=$(echo $line | /usr/bin/awk ' {print $9}')
    mois_nasback=$(echo $line | /usr/bin/awk ' {print $8}')

    # ON GARDE LE FICHIER DU 10 DU MOIS
    if [ "$jour_nasback" -eq 10 ] && [ "$mois_nasback" == "$mois_precedent" ]
    then    echo "fichier a DEPLACER"
            echo $(echo $line | /usr/bin/awk ' {print $11}')

    # ON GARDE LE FICHIER DU 20 DU MOIS
    elif [ "$jour_nasback" -eq 20 ] && [ "$mois_nasback" = "$mois_precedent" ]
    then    echo "fichier a DEPLACER"
            echo $(echo $line | /usr/bin/awk ' {print $11}')

    # ON GARDE LE FICHIER DU 30 DU MOIS
    elif [ "$jour_nasback" -eq 30 ] && [ "$mois_nasback" = "$mois_precedent" ]
    then    echo "fichier a DEPLACER"
            echo $(echo $line | /usr/bin/awk ' {print $11}')

    # ON GARDE LE FICHIER DU 28 DU MOIS DE FEVRIER
    elif [ "$jour_nasback" -eq 28 ] && [ "$mois_nasback" = "$mois_fevrier" ]
    then    echo "fichier a DEPLACER"
            echo $(echo $line | /usr/bin/awk ' {print $11}')

    # SUPPRESSION DES AUTRES FICHIERS
    elif [ "$mois_nasback" = "$mois_precedent" ]
    then    echo "fichier a supprimer"

    # NORMALEMENT INUTILE
    else    echo "fichier inconnu"

fi

done[/code]

Je remplacerai les echos par rm le mois prochain quand j’aurai des fichiers à supprimer et après vérification !

Merci encore à tous pour vos réponses

substr de Perl :
$nouvelle_chaine=substr($chaine, rang, nombre)
où rang est le rang du caractère de départ ( -6 dans mon exemple ) et nombre le nombre de caractère à substituer ( par rien, dans cette syntaxe ! )
-1 est le dernier caractère, -2 le précédent etc…
si ta chaine a toujours la même longueur, tu peux évidemment utiliser un rang à partir de 0 (le rang du 1er caractère),
-6 , 6 devrait donc enlever tout ce qui est à la fin ( les 6 derniers caractères )

Donne moi un exemple ( le nom d’un fichier et ta ligne de commande avec perl car j’ai un peu oublier le mien… )

Mais si tu ne veux pas apprendre Perl, écoute plutôt les autres. avec seulement bash, +/- sed et awk on peut aussi le faire.