Pregunta

Estoy escribiendo scripts de shell donde se escriben regularmente algunas cosas en un archivo, después de lo cual se ejecuta una aplicación que lee ese archivo.Encuentro que a través de nuestra empresa la latencia de la red difiere enormemente, por lo que una simple sleep 2 por ejemplo, no será lo suficientemente robusto.

Intenté escribir un bucle de tiempo de espera (configurable) como este:

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
}

Esto funciona para test="[ -e $somefilename ]".Sin embargo, probar la existencia no es suficiente; a veces necesito probar si se escribió una determinada cadena en el archivo.Lo intentétest="grep -sq \"^sometext$\" $somefilename", pero esto no funciono.¿Alguien puede decirme por qué?

¿Existen otras opciones menos detalladas para realizar dicha prueba?

¿Fue útil?

Solución

Puede establecer la variable de prueba de la siguiente manera:

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

La razón de su grep no funciona es que las citas son muy difíciles de pasar en los argumentos. Tendrá que utilizar eval:

if ! eval $test

Otros consejos

Yo diría la manera de comprobar si hay una cadena en un archivo de texto es grep.

¿Cuál es su problema exacto con ella?

También es posible ajustar su montaje NFS parámetros, para deshacerse de la raíz del problema. Una sincronización también podría ayudar. Ver documentos NFS.

Si tienes intención de utilizar waitLoop en un "si", es posible que desee cambiar la "salida" a un "retorno", por lo que el resto de la secuencia de comandos puede manejar la situación de error (no hay ni siquiera un mensaje a al usuario sobre lo que falló antes del script muere de otra manera).

El otro problema es el uso de "$ test" para sostener un comando significa que no obtiene el desarrollo del forro cuando en realidad la ejecución, simplemente evaluando. Así que si usted dice test = "grep \" foo \ "\ 'barra de Baz \'", en lugar de buscar la cadena foo tres letras en el archivo con el nombre de la barra de siete caracteres Baz, que va a buscar los cinco char string "foo" en el archivo de nueve char "barra de Baz".

Así que usted puede decidir que no es necesario que la magia cáscara, y la prueba de establecer = 'grep ^ -sq SomeText $ somefilename', o puede obtener la cáscara para manejar la cita explícitamente con algo como:

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

Trate de usar el tiempo de modificación de archivos para detectar cuando se escribe sin abrirlo. Algo así como

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

Esto no funcionará, sin embargo, si varios procesos intentan acceder al archivo al mismo tiempo.

Acabo de tener exactamente el mismo problema.Utilicé un enfoque similar al tiempo de espera que incluyes en tu OP;sin embargo, también incluí una verificación del tamaño del archivo.Restablezco mi temporizador de tiempo de espera si el archivo ha aumentado de tamaño desde la última vez que se revisó.Los archivos que estoy escribiendo pueden ocupar unos pocos gigas, por lo que tardan un poco en escribirse a través de NFS.

Esto puede ser excesivo para su caso particular, pero también hice que mi proceso de escritura calculara un hash del archivo una vez que terminó de escribir.Usé md5, pero algo como crc32 también funcionaría.Este hash se transmitió desde el escritor a los (múltiples) lectores, y el lector espera hasta que a) el tamaño del archivo deje de aumentar y b) el hash (recién calculado) del archivo coincida con el hash enviado por el escritor.

Tenemos un problema similar, pero por diferentes razones. Estamos leyendo el archivo s, que se envía a un servidor SFTP. La máquina que ejecuta la secuencia de comandos no es el servidor SFTP.

Lo que he hecho es configurarlo en cron (aunque un bucle con un sueño funcionaría también) para hacer un cksum del archivo. Cuando el viejo cksum coincide con el cksum actual (el archivo no ha cambiado por la cantidad de tiempo determinado) sabemos que las escrituras están completos, y transferir el archivo.

Sólo para estar seguro extra, nunca sobrescribir un archivo local antes de hacer una copia de seguridad, y sólo la transferencia en absoluto cuando el archivo remoto tiene dos cksums en una fila que coincide, y que cksum no coincide con el archivo local.

Si necesitas ejemplos de código, estoy seguro de que puedo desenterrarlos.

La cáscara se estaba dividiendo su predicado en palabras. Coge todo con $@ como en el código siguiente:

#! /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"

Salida:

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

Lástima que el manuscrito no es tan interesante como ver en tiempo real.

No está mal ... es un poco loco ...

Si usted tiene control sobre el archivo: usted puede ser capaz de crear una 'tubería con nombre' aquí. Así que (dependiendo de cómo el programa de escritura funciona) puede supervisar el archivo de una manera sincronizada.

En su forma más simple:

Crea la canalización con nombre:

mkfifo file.txt

Configurar el receptor sincronización:

while :
do
    process.sh < file.txt
end

Crear un emisor de prueba:

echo "Hello There" > file.txt

El 'process.sh' es donde va tu lógica: esto bloqueará hasta que el remitente ha escrito su salida. En teoría, el programa de escritor no necesitará modifiying ....

ADVERTENCIA: Si el receptor no está funcionando por algún motivo, puede terminar bloqueando el remitente

No está seguro de que se ajuste a sus necesidades aquí, pero podría ser vale la pena analizar.

O para evitar sincronizada, intente 'lsof'?

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

Si se asume que sólo desea leer el archivo cuando nada está escribiendo a la misma (es decir, el proceso de escritura ha terminado?) - se puede comprobar si nada más tiene identificador de archivo a ella

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top