1 votes

trouver les identifiants de fichiers correspondants dans les fichiers de données du répertoire et les copier dans un autre répertoire.

J'ai un file_id = 840920 et je dois choisir uniquement les fichiers enfants qui appartiennent au file_id = 840920 . Les noms des fichiers de données sont différents mais dans tous les fichiers de données, l'identifiant du fichier parent est disponible. L'exemple d'un enregistrement est le suivant :

445973129|2602325065|840920|1|RUPATXEM14|LVP|||20180924 18:25:10
445973130|2602325066|840920|2|RP_STG_TEST_WED|LVP|||20180924 18:23

Je veux donc mapper ma recherche uniquement pour la troisième colonne, extraire ces fichiers de données et les copier dans un autre dossier.

Voici mon code sous unix pour faire la même chose. J'ai besoin d'un peu d'aide pour obtenir plus de suggestions ou de meilleures façons de gérer la même chose. Ma question est que je suis capable d'imprimer matched_file_id lorsque j'exécute la boucle while séparément, mais le code ne s'imprime pas en montrant la matched_file_id lorsque je les ai inclus dans mon code : Des suggestions, s'il vous plaît ?

cat $TMP/TempBatchData.txt | while read FILE_ID #FILE_ID = 840920
do
for file in *CDI*.dat; do
echo $file >> all_CDI_LIST.txt
done
while IFS= read -r line; do
matched_file_id=`cat $line | cut -f3 -d"|" | sort -u` # echo all the third 
column values
done < "all_CDI_LIST.txt" 

if [[ $matched_file_id == $FILE_ID ]]; then 
echo $line >> final_cdi_list.txt
fi
done
done

0voto

Kamil Maciorowski Points 57004

Des problèmes, des fragments suspects :

  • $matched_file_id contient zéro ou plusieurs valeurs, la comparaison avec $FILE_ID ne réussit que lorsqu'il y a une seule valeur ;
  • $matched_file_id est défini une fois par line par rapport à $FILE_ID est effectuée une fois par FILE_ID ;
  • il y a un supplément done à la fin ( ?);
  • column values doit appartenir à un commentaire ;
  • Les variables ne sont pas citées ;
  • TMP doit être défini.

Il s'agit d'une procédure réécrite. Ce n'est pas complètement équivalent mais l'approche semble meilleure :

TMP="/the/right/path"
find . -type f -name '*CDI*.dat' \
       -exec sh -c '
          <"$1" cut -f3 -d"|" | grep -qFx -f "$TMP/TempBatchData.txt"
       ' sh {} \; -print > final_cdi_list.txt

Explication :

  1. find trouve tous les fichiers correspondant à l'option *CDI*.dat modèle.
  2. Pour chaque fichier de ce type, un Shell est exécuté pour traiter un tuyau.
  3. cut extrait la troisième colonne.
  4. grep tranquillement ( -q ) vérifie si une chaîne littérale ( -F ) à partir du fichier donné ( -f ) existe dans la sortie de cut comme une ligne entière ( -x ).
  5. Si c'est le cas, find imprimera le chemin d'accès au fichier.

Notes, différences, bizarreries :

  • find agit de manière récursive. Pour traiter uniquement le répertoire courant sans les sous-répertoires, vous avez besoin de -maxdepth 1 (non requis par POSIX) ou une solution POSIX de cette question ou laisser le Shell s'étendre. *CDI*.dat ( find *CDI*.dat -type f -exec … ) qui a ses inconvénients.

  • find imprimera les chemins avec le premier ./ . Pour obtenir les noms de base, vous devez -printf '%f\n' (non-POSIX) au lieu de -print ou par exemple -exec basename {} \; (conforme à POSIX) au lieu de -print .

  • grep -F correspond à des chaînes de caractères littérales. Dans votre code, chaque ligne de $TMP/TempBatchData.txt subit deux fois un traitement implicite :

    1. avec read FILE_ID (par opposition à read -r FILE_ID ),
    2. à l'intérieur de la [[ $matched_file_id == $FILE_ID ]] (comparaisons utilisant [[ effectuer une comparaison de motifs avec la chaîne non citée du côté droit, et non une simple comparaison de chaînes de caractères).

    Je ne sais pas si vous comptez sur ça. Vous pourriez vouloir ajuster mon code.

  • Le titre mentionne la copie de fichiers dans un autre répertoire. Avec mon approche vous n'avez pas besoin de traiter final_cdi_list.txt pour le faire. Il suffit d'utiliser -exec cp {} "/another/directory" \; au lieu de -print .

Tout le travail de recherche de fichiers qui correspondent peut être fait avec une seule et unique. grep Vous devez cependant ajuster le modèle. Par exemple :

grep -l '^[0-9]*|[0-9]*|840920|' *CDI*.dat

Vous pouvez avoir plusieurs motifs dans un fichier ( -f "$TMP/TempBatchData.txt" ) mais ils doivent être comme ceux mentionnés ci-dessus. S'il y a trop de fichiers correspondant *CDI*.dat vous obtiendrez "liste d'arguments trop longue" (l'approche avec les for file in *CDI*.dat; que vous avez utilisé à l'origine est immunisé contre cela).

Peut-être ajuster votre structure de répertoire (par exemple, seulement *CDI*.dat dans le répertoire courant et les sous-répertoires, recherche récursive autorisée ou pas de sous-répertoires du tout) et le format du fichier de motifs. L'idée est d'utiliser

grep -lr -f "$TMP/TempBatchData.txt"

ou quelque chose de similaire. Note -r n'est pas requis par POSIX, dans cet exemple sa signification est celle de GNU grep : lire tous les fichiers sous le répertoire de travail actuel, de manière récursive.

Un seul grep devrait être plus rapide que toute solution qui utilise find -exec o read (et fait correspondre les chaînes de caractères de n'importe quelle manière).

SistemesEz.com

SystemesEZ est une communauté de sysadmins où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres sysadmins, poser vos propres questions ou résoudre celles des autres.

Powered by:

X