Copier une arborescence complète par FTP
Pour copier une arborescence complète en utilisant un client FTP basique qui n’est pas capable de récupérer récursivement un ensemble de répertoires et sous-répertoires.
#!/bin/ksh
# Copie une arborescence complete par FTP
# Usage :
# ftp -n < <(ksh ./ftp_upload_tree.sh SOURCE DESTINATION USERNAME PASSWORD HOSTNAME)
SOURCE="$1"
DESTINATION="$2"
USER="$3"
PASSWORD="$4"
HOSTNAME="$5"
# ----------------------------------
printf 'open "%s"\n' "$HOSTNAME"
printf 'user "%s" "%s"\n' "$USER" "$PASSWORD"
cd "$SOURCE"
old_rep=""
while IFS= read -r fic; do
if [ -d "$fic" ]; then
printf 'mkdir "%s/%s"\n' "$DESTINATION" "$fic"
elif [ -f "$fic" ]; then
rep=$(dirname "$fic")
if [[ "$rep" != "$old_rep" ]]; then
old_rep="$rep"
printf 'cd "%s/%s"\n' "$DESTINATION" "$rep"
printf 'lcd "%s/%s"\n' "$SOURCE" "$rep"
fi
basefic=$(basename "$fic")
printf 'put "%s"\n' "$basefic"
fi
done < <(find . -print|sort)
printf "bye\n"
# EOF
Récupérer les permissions
Récupérer les droit unix d’un répertoire sous forme numérique (ex. 750
pour drwxr-x--
) :
# Usage : get_octal_permission_for_directory /home/myrep
get_octal_permission_for_directory()
{
ls -ld $1| awk '{k=0;for(i=0;i<=8;i++)k+=((substr($1,i+2,1)~/[rwx]/)*2^(8-i));if(k)printf("%0o",k);}'
}
Récupérer les droit unix d’un fichier sous forme numérique (ex. 750
pour -rwxr-x--
) :
# Usage : get_octal_permission_for_file /home/myrep/myfile
get_octal_permission_for_file()
{
ls -l $1| awk '{k=0;for(i=0;i<=8;i++)k+=((substr($1,i+1,1)~/[rwx]/)*2^(8-i));if(k)printf("%0o",k);}'
}
Renommer des fichiers dont le nom contient des espaces
Pour traiter l’ensemble des répertoire, lancer plusieurs fois (dépend du nombre de sous répertoires imbriqués) :
find . -type d | sed -e "s/.*/\"&\"/g;p;y/\ /_/" | xargs -n2 mv
Pour traiter l’ensemble des fichiers une fois que les répertoires sont propres :
find . -type f | sed -e "s/.*/\"&\"/g;p;y/\ /_/" | xargs -n2 mv
Comparaison de fichiers / droits entre deux plateformes
Ce script est utile pour comparer une arborescence de fichiers entre deux serveurs et mettre en évidence des différences entre les droits et propriétaires de fichiers ou des différences de taille.
Sur les deux serveurs à comparer, il faut extraire la liste des fichiers dans l’arborescence où l’on souhaite effectuer la comparaison au moyen de la procédure qui suit.
Sur le serveur de référence
find /applis/projects/PROD/directory -ls > /tmp/serveur_de_reference.txt
Sur le serveur à comparer
find /applis/projects/PROD/directory -ls > /tmp/serveur_a_comparer.txt
Astuce : si dans le chemin un nom de répertoire est dépendant du serveur ou de l’installation, il peut être utile de le modifier avec sed lors de la génération pour permettre une comparaison indépendante de la plateforme :
find /applis/projects/PROD/directory -ls | sed s/pcyym14p6/SERVEUR/g > /tmp/serveur_de_reference.txt
Comparaison des fichiers résultats
Ensuite, rapatrier les deux fichiers sur votre poste et lancer d’utilitaire :
comparateur.py serveur_de_reference.txt serveur_a_comparer.txt > resultat.csv
Le code est visible en fin d’article et vous pouvez le télécharger ici : comparateur.py.
Options possibles
Quelques options sont possibles :
-d
: répertoire. Compare uniquement les répertoires (donc juste les droits et les propriétaires)-t
: taille. Compare la taille des fichiers en plus des comparaisons standards. Cet argument ne sert à rien si l’argument -d est utilisé-h
: aide
Un mode correctif est possible :
-u
: affichage des suggestions de commandes pour la correction des UID-g
: affichage des suggestions de commandes pour la correction des GID-p
: affichage des suggestions de commandes pour la correction des permissions
Traitement des résultats
Le fichier généré est un fichier CSV utilisable avec OpenOffice ou Excel. Il comprend quatre colonnes :
- Raison : la raison de la remontée
- Fichier : le chemin du fichier concerné
- Attendu : l’état attendu (sur le serveur de référence)
- Trouve : l’état trouvé (sur le serveur à comparer)
Raison | Fichier | Attendu | Trouve |
---|---|---|---|
FNF |
htdocs/WebHelp.4/whskin_tbars.htm |
-rwxr-x--- |
3458 |
FNF |
htdocs/WebHelp.1/whgdata/whlstf56.htm |
-rwxr-x--- |
40357 |
FEP |
Plugins/config/WebSrv02 |
drwxr-x--- |
256 |
Pour les raisons, voici les typologies remontées :
FNF
: Fichier présent sur le serveur de référence mais non trouvé sur le serveur cibleDNC
: Droits non conformes entre les deux serveursUID
: Le propriétaire du fichier est différentGID
: Le groupe propriétaire du fichier est différentTNC
: Taille non conforme entre les deux serveursFEP
: Fichier en plus. Présent sur le serveur à comparer, mais pas sur le serveur de référence
Code de comparateur.py
Voici le code de comparateur.py
:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
comparateur.py - version and date, see below
Author : Alexandre Norman - norman at xael.org
Licence : GPL v3 or any later version
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
===============
Documentation :
===============
Ce script permet de comparer deux environnements. Il faut
lui fournir la liste des fichiers de ces deux environnements
issues de la commande 'find . -ls'
"""
__author__ = 'Alexandre Norman (norman at xael.org)'
__version__ = '0.2.0'
__last_modification__ = '2014.07.27'
import sys
try:
import clize
except ImportError:
print("This program uses clize. See : https://github.com/epsy/clize")
sys.exit(1)
############################################################################
def analyse_fichier(fichier, uniquement_repertoires=False):
"""
Recupere la sortie d'une commande 'find . -ls' et la transforme en objets analysables.
"""
with open(fichier) as file_handle:
all_files = {}
for line in file_handle.readlines():
# 50725038 4 drwxrwxr-x 7 xael xael 4096 Oct 21 00:10 ../actuvelo_veilleurs
try:
inode, size_in_block, droits, unknow, uid, gid, taille, month, day, time_or_year = line.split()[0:10]
except ValueError:
print('ERR', line[0:67], line[0:67].split())
if uniquement_repertoires:
if droits[0] != 'd':
continue
filename = ' '.join(line.split()[10:]).strip()
all_files[filename] = {
'droits': droits,
'uid': uid,
'gid': gid,
'taille': taille,
'month': month,
'day': day,
'time_or_year': time_or_year
}
return all_files
############################################################################
def print_error(raison, fichier, attendu='', trouve=''):
"""
Affiche l'erreur au format CSV
"""
print('"{0}";"{1}";"{2}";"{3}"'.format(raison, fichier.replace('"', '""'),
attendu.replace('"', '""'),
trouve.replace('"', '""')))
return
############################################################################
def conversion_droits(droits):
"""
"""
def doctal(droits):
"""
"""
doct = 0
if 'r' in droits:
doct += 4
if 'w' in droits:
doct += 2
if 'x' in droits:
doct += 1
return str(doct)
uid = droits[1:4]
gid = droits[4:7]
others = droits[7:10]
return doctal(uid) + doctal(gid) + doctal(others)
############################################################################
def analyse(reference="liste_originale.txt", a_comparer="liste_modifiee.txt",
uniquement_repertoires=False, comparaison_taille=False, correction_uid=False,
correction_gid=False, correction_permissions=False):
"""
Analyse les fichiers fournis en entree
"""
fr = analyse_fichier(reference, uniquement_repertoires)
ac = analyse_fichier(a_comparer, uniquement_repertoires)
mode_correction = correction_permissions or correction_gid or correction_uid
if not mode_correction:
print_error('Raison', 'Fichier', 'Attendu', 'Trouve')
for fichier in fr:
if uniquement_repertoires:
if fr[fichier]['droits'][0] != 'd':
continue
if fichier not in ac:
# FNT : Fichier non trouve
if not mode_correction:
print_error('FNF', fichier, fr[fichier]['droits'], fr[fichier]['taille'])
else:
if fr[fichier]['droits'] != ac[fichier]['droits']:
# DNC : Droits non conformes
if not mode_correction:
print_error('DNC', fichier, fr[fichier]['droits'], ac[fichier]['droits'])
elif correction_permissions:
print('chmod {1} {0}'.format(fichier, conversion_droits(fr[fichier]['droits'])))
if fr[fichier]['uid'] != ac[fichier]['uid']:
# UID : Uid non conforme
if not mode_correction:
print_error('UID', fichier, fr[fichier]['uid'], ac[fichier]['uid'])
elif correction_uid:
print('chown {1} {0}'.format(fichier, fr[fichier]['uid']))
if fr[fichier]['gid'] != ac[fichier]['gid']:
# GID : Gid non conforme
if not mode_correction:
print_error('GID', fichier, fr[fichier]['gid'], ac[fichier]['gid'])
elif correction_gid:
print('chgrp {1} {0}'.format(fichier, fr[fichier]['gid']))
if not mode_correction:
if fr[fichier]['droits'][0] != 'd' and comparaison_taille and fr[fichier]['taille'] != ac[fichier]['taille']:
# TNC : Taille non conforme
print_error('TNC', fichier, fr[fichier]['taille'], ac[fichier]['taille'])
if not mode_correction:
for fichier in ac:
if ac[fichier]['droits'][0] != 'd':
continue
if not fichier in fr:
# FEP : Fichier en plus
print_error('FEP', fichier, ac[fichier]['droits'], ac[fichier]['taille'])
return
############################################################################
def __show_version__(name, **kwargs):
"""
Show version
"""
import os
print("{0} version {1}".format(os.path.basename(name), __version__))
return True
############################################################################
@clize.clize(
alias = {
'reference': ('r',),
'compare': ('c',),
'taille': ('t',),
'repertoires': ('d',),
'correction_uid': ('u',),
'correction_gid': ('g',),
'correction_permissions': ('p',),
},
extra = (
clize.make_flag(
source=__show_version__,
names=('version', 'v'),
help="Show the version",
),
)
)
def __main__(reference, compare, repertoires=False, taille=False, correction_uid=False, correction_gid=False, correction_permissions=False):
"""
comparateur.py
reference: nom du fichier de reference
compare: nom du fichier a comparer
taille: compare egalement la taille
repertoires: compare uniquement les repertoires
Ce script permet de comparer deux environnements. Il faut
lui fournir la liste des fichiers de ces deux environnements
issues de la commande 'find . -ls' en tant que reference et compare
Written by : Alexandre Norman <norman at xael.org>
"""
analyse(reference=reference, a_comparer=compare, uniquement_repertoires=repertoires,
comparaison_taille=taille, correction_uid=correction_uid,
correction_gid=correction_gid, correction_permissions=correction_permissions)
return
############################################################################
# MAIN -------------------
if __name__ == '__main__':
clize.run(__main__)
sys.exit(0)
#<EOF>######################################################################