1
votes

Comment parcourir les lignes d'un fichier et lire les champs dans des variables

J'ai un fichier hotfix_final qui ressemble à ceci:

usage_type=$( cat /opt/abc/ps/usage.txt )
current_date=$( date +%x )
lines=$( wc -l /home/abc/hotfix_final | awk '{print $1}' )

count=0

while $count <= $lines; do

    hf_link=$( awk if( NR=$count ) '{print $1}' hotfix_final )
    relase_date=$( awk if( NR=$count ) '{print $2}' hotfix_final )
    count=$(( count+1 ))

done < hotfix_final

J'ai besoin d'écrire un script shell qui lit le fichier ligne par ligne puis prend la date qui est à côté du lien dans une variable afin que je puisse le comparer à la date actuelle. Si les dates sont égales et usage_type = 4 , j'ai besoin du script pour obtenir le lien.

Ce que j'ai essayé jusqu'à présent:

https://download.abc.com  06/24/2019
https://download.abc.com  06/26/2019
https://download.abc.com  07/05/2019
  • $ lines pour afficher le nombre maximum de lignes à lire.

  • $ hf_link pour obtenir le lien

  • $ release_date pour obtenir la date à côté de $ hf_link

Maintenant, je ne sais pas comment écrire la partie qui vérifie si $ usage_type == 4 et $ current_date = $ relase_date sont vrais, et si oui, wget le lien. Cela doit être fait individuellement pour chaque ligne du fichier.


2 commentaires

Il y a beaucoup de nombreuses erreurs dans ce script. (1) : citez correctement votre awk: awk '{if (NR == $ count) print $ 1}' (2) instructions if devrait faire des comparaisons et non des affectations: if (NR == $ count) (3) les variables shell doivent être passées à awk correctement: awk -v count = $ count '{if (NR == count) print $ 1}' (4) n'analysez pas un fichier en bash avec une boucle while comme vous le faites :, utilisez simplement un while correct en combinaison avec read, vous pouvez sauter le awk pour extraire les variables. Voir la réponse de Léa Gris


Voir stackoverflow.com/a/38627863/874188 pour savoir pourquoi la lecture des numéros de ligne est très souvent un anti-modèle.


3 Réponses :


4
votes

Peut être fait avec quelques corrections de votre script:

  • Vous devez prendre soin de citer vos variables pour éviter que les valeurs ne soient fractionnées sur un espace ou sur des caractères répertoriés dans la variable $ IFS .

  • date +% x renverrait une date avec un format différent sur un système avec des paramètres régionaux différents dans la variable d'environnement $ LC_TIME .
    Le format % x serait MM / JJ / AA lors du réglage de LC_TIME = en_US , mais il y a une petite chance (bien que très peu probable) que les paramètres régionaux en_US peuvent ne pas être disponibles pour le système.
    Il est alors préférable d'utiliser un format explicite indépendant des paramètres régionaux de +% d /% m /% Y , pour être sûr du format de date.

Voici une version fixe:

#!/usr/bin/env bash
# Early exit this script if the usage.txt file does not contain the value 4
grep -Fqx 4 /opt/abc/ps/usage.txt || exit

# Store current date in the MM/DD/YYYY format
current_date="$(date +%d/%m/%Y)"

# Iterate each line from hotfix_final
# and read the variables hf_link and release_date
while read -r hf_link release_date; do
  if [ "$current_date" = "$release_date" ]; then
    wget "$hf_link"
  fi
done </home/abc/hotfix_final # Set the file as input for the whole while loop


5 commentaires

mais comment le shell sait-il que pour chaque ligne du fichier hotfix_final $ hf_link représente les liens tandis que $ release_date représente les dates à côté des liens?


La commande read lit une ligne à la fois. Ensuite, lorsqu'il est présenté avec plusieurs variables à lire, il utilise des espaces ou les caractères définis dans la variable d'environnement $ IFS pour délimiter les champs dans la ligne et affecter des valeurs aux variables dans le même ordre que les arguments des variables lues.


Vous voulez quitter tôt si usage_type n'est pas 4, au lieu de le comparer encore et encore à l'intérieur de la boucle.


Vous l'avez seulement déplacé, il est toujours comparé à chaque itération.


Désolé pour la faute de frappe fgrep -f dans ma réponse, vous voulez corriger cela ici aussi.



1
votes

Voici une refactorisation de la réponse acceptée pour éviter la boucle fugace while read -r .

#!/bin/sh

grep -Fqx 4 /opt/abc/ps/usage.txt || exit

awk -v current_date="$(date +%d/%m/%Y)" '
    $2 == current_date { print $1 }' /home/abc/hotfix_final |
xargs -r -n 1 wget

L'option -r pour xargs est une extension GNU; si vous ne l'avez pas, ce n'est pas critique, mais cela permet d'éviter un message d'erreur lorsque le script Awk ne produit aucune sortie.

Dans votre prochain projet, vous voulez vous assurer d'utiliser un moins insensé format de date dans des fichiers lisibles par ordinateur.


2 commentaires

Je suppose que vous pouvez le faire dans un script awk autonome avec son propre #! / Usr / bin / env awk shebang


J'ai aussi commencé avec la gestion de usage.txt dans le script Awk, mais cela avait moins de sens pour quelqu'un qui n'est probablement pas très familier avec Awk, donc je voulais le garder très simple et structuré.



0
votes

Cela pourrait fonctionner pour vous (GNU Parallel):

[ $(<usageFile) -eq 4 ] && 
parallel -a fixFile -C' +' [ {2} = $(date +%m/%d/%Y) ] \&\& wget {1}

Utilisez test pour interroger le fichier d'utilisation et s'il est défini sur 4 utilisez le parallèle pour terminer la tâche. Parallel utilise le fichier fix et l'option -C avec l'expression rationnelle d'un ou plusieurs espaces pour nommer les colonnes du fichier {1} comme l'url et {2} comme date. Le test est utilisé à nouveau pour vérifier la colonne de date par rapport à la date d'aujourd'hui et une correspondance wget l'URL.


0 commentaires