Question

Je l'écriture de scripts shell où assez régulièrement des choses est écrit dans un fichier, après quoi une application est exécutée qui lit ce fichier. Je trouve que grâce à notre société le temps de latence du réseau diffère considérablement, si simple, par exemple sleep 2 sera pas assez robuste.

I essayé d'écrire une boucle de temporisation (configurable) comme suit:

waitLoop()
{
   local timeout=$1
   local test="$2"

   if ! $test
   then
      local counter=0
      while ! $test && [ $counter -lt $timeout ]
      do
         sleep 1
         ((counter++))
      done

      if ! $test
      then
         exit 1
      fi
   fi
}

Cela fonctionne pour test="[ -e $somefilename ]". Cependant, l'essai existence ne suffit pas, il me faut parfois vérifier si une chaîne a été écrite dans le fichier. j'ai essayé test="grep -sq \"^sometext$\" $somefilename", mais cela ne fonctionne pas. Quelqu'un peut-il me dire pourquoi?

Y at-il d'autres options moins verbeux pour effectuer un tel test?

Était-ce utile?

La solution

Vous pouvez définir votre variable de test de cette façon:

test=$(grep -sq "^sometext$" $somefilename)

La raison pour laquelle votre grep ne fonctionne pas est que les guillemets sont vraiment difficiles à passer des arguments. Vous aurez besoin d'utiliser eval:

if ! eval $test

Autres conseils

Je dirais que moyen de vérifier une chaîne dans un fichier texte est grep.

Quel est votre problème exact avec elle?

Aussi, vous pouvez régler vos paramètres de montage NFS, pour se débarrasser du problème de la racine. Une synchronisation peut également aider. Voir docs NFS.

Si vous êtes désireux d'utiliser waitLoop dans un « si », vous voudrez peut-être changer la « sortie » à un « retour », de sorte que le reste du script peut gérer la situation d'erreur (il n'y a même pas un message à l'utilisateur sur ce qui a échoué avant que le script meurt autrement).

L'autre question utilise « $ test » pour maintenir une commande signifie que vous ne recevez pas l'expansion du shell alors qu'en réalité, l'exécution, l'évaluation juste. Donc, si vous dites test = « grep \ » foo \ « \ « bar baz \ » », plutôt que de chercher la chaîne trois lettres foo dans le fichier avec la barre de nom de sept caractères baz, il va chercher les cinq cordes omble chevalier "toto" dans le fichier de neuf char "bar baz".

Vous pouvez vous décider ne pas besoin de la magie de la coquille, et le test set = « grep -sq ^ someText $ somefilename », ou vous pouvez obtenir le shell pour gérer la citant explicitement avec quelque chose comme:

if /bin/sh -c "$test"
then
   ...

Essayez d'utiliser le temps de modification de fichier pour détecter le moment où il est écrit sans l'ouvrir. Quelque chose comme

old_mtime=`stat --format="%Z" file`
# Write to file.
new_mtime=$old_mtime
while [[ "$old_mtime" -eq "$new_mtime" ]]; do 
  sleep 2;
  new_mtime=`stat --format="%Z" file`
done

Cela ne fonctionnera pas, cependant, si plusieurs processus tentent d'accéder au fichier en même temps.

Je viens d'avoir le même problème. J'ai utilisé une approche similaire à l'attente du délai d'attente que vous incluez dans votre OP; cependant, j'ai aussi inclus un chèque de taille de fichier. Réinitialiser mon minuteur de délai d'attente si le fichier a augmenté en taille depuis la dernière, il a été vérifié. Les fichiers que je suis en train d'écrire peut être un peu concert, ils prennent un certain temps à écrire dans NFS.

Cela peut être surpuissant pour votre cas particulier, mais j'avais aussi mon processus d'écriture calculer un hachage du fichier après qu'il a été fait par écrit. Je md5, mais quelque chose comme CRC32 travaillerais aussi. Ce hachage a été diffusé de l'écrivain aux (multiples) lecteurs, et le lecteur attend que a) la taille du fichier cesse d'augmenter et b) le hachage du fichier (fraîchement calculé) correspond au hachage envoyé par l'auteur.

Nous avons un problème similaire, mais pour des raisons différentes. Nous lisons fichier s, qui est envoyé à un serveur SFTP. La machine exécutant le script est pas le serveur SFTP.

Ce que je l'ai fait est mis en place dans Cron (bien qu'une boucle avec un sommeil fonctionnerait aussi) pour faire un cksum du fichier. Lorsque l'ancien cksum correspond à la cksum actuelle (le fichier n'a pas changé pour la quantité déterminée de temps), nous savons que les écritures sont terminées, et transférer le fichier.

Pour être remplacer plus de sécurité, nous ne un fichier local avant d'effectuer une sauvegarde et le transfert qu'à tout lorsque le fichier distant a deux cksums dans une rangée qui correspondent, et que cksum ne correspond pas au fichier local.

Si vous avez besoin d'exemples de code, je suis sûr que je peux les déterrer.

La coque fendait votre prédicat en mots. Prenez tout avec comme dans le $@ Code ci-dessous:

#! /bin/bash

waitFor()
{
  local tries=$1
  shift
  local predicate="$@"

  while [ $tries -ge 1 ]; do
    (( tries-- ))

    if $predicate >/dev/null 2>&1; then
      return
    else
      [ $tries -gt 0 ] && sleep 1
    fi
  done

  exit 1
}

pred='[ -e /etc/passwd ]'
waitFor 5 $pred
echo "$pred satisfied"

rm -f /tmp/baz
(sleep 2; echo blahblah >>/tmp/baz) &
(sleep 4; echo hasfoo   >>/tmp/baz) &

pred='grep ^hasfoo /tmp/baz'
waitFor 5 $pred
echo "$pred satisfied"

Sortie:

$ ./waitngo 
[ -e /etc/passwd ] satisfied
grep ^hasfoo /tmp/baz satisfied

Dommage que le tapuscrit est pas aussi intéressant que regarder en temps réel.

Ok ... c'est un peu déjanté ...

Si vous avez le contrôle sur le fichier: vous pourriez être en mesure de créer un « pipe nommé » ici. Donc (selon la façon dont le programme d'écriture fonctionne), vous pouvez surveiller le dossier de façon synchronisée.

Au plus simple:

Créer le canal nommé:

mkfifo file.txt

Configurer le récepteur synchronisation:

while :
do
    process.sh < file.txt
end

Créer un expéditeur de test:

echo "Hello There" > file.txt

Le « process.sh » est où votre logique va: cela va bloquer jusqu'à ce que l'expéditeur a écrit sa sortie. En théorie, le programme écrivain n'a pas besoin .... Sa modification

AVERTISSEMENT: si le récepteur ne fonctionne pas pour une raison quelconque, vous pouvez finir par bloquer l'expéditeur

Je ne sais pas qu'il correspond à vos besoins, mais peut-être dignes d'intérêt.

Ou pour éviter synchronisé, essayez lsof '?

http://en.wikipedia.org/wiki/Lsof

En supposant que vous ne voulez lire à partir du fichier quand rien d'autre écrit à (ie, le processus d'écriture a terminé) - vous pouvez vérifier si rien n'a d'autre descripteur de fichier à ce

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top