Mi problema (en una secuencia de comandos con #!/bin/sh
) es el siguiente: Intento sumar todos los archivos en un directorio con fines de archivo. El archivo de suma de comprobación (en mi caso sha1) con todos los nombres de archivo debe residir en el mismo directorio. Digamos que tenemos un directorio ~/test
con archivos f1
y f2
:.
mkdir ~/test
cd ~/test
echo "hello" > f1
echo "world" > f2
Ahora calculando las sumas de verificación con
find -maxdepth 1 -type f -printf '%P\n' | xargs shasum
hace exactamente lo que quiero, enumera todos los archivos del directorio actual y calcula las sumas sha1 (la profundidad máxima se puede cambiar más adelante). La salida en STDOUT es:
f572d396fae9206628714fb2ce00f72e94f2258f f1
9591818c07e900db7e1e0bc4b884c945e6a61b24 f2
Desafortunadamente, al intentar guardar esto en un archivo con
find -maxdepth 1 -type f -printf '%P\n' | xargs shasum > sums.sha1
el archivo resultante muestra la suma de comprobación por sí mismo:
da39a3ee5e6b4b0d3255bfef95601890afd80709 sums.sha1
f572d396fae9206628714fb2ce00f72e94f2258f f1
9591818c07e900db7e1e0bc4b884c945e6a61b24 f2
y, por lo tanto, falla más tarde shasum --check
, debido al obvio problema de la modificación de archivos adicionales al guardar la última suma.
Miré a mi alrededor y al usar -p
flag for xargs
, descubrí que de alguna manera crea el archivo de salida antes de incluso ejecutar el comando find, por lo tanto, se encuentra el archivo adicional y se sumará a la suma de comprobación ...
Sé que, como solución alternativa, podría guardar la suma de comprobación en otra ubicación (directorio temporal a través de mktemp
) o excluirla en find específicamente, pero me gustaría entender por qué se comporta de la manera en que lo hace, lo que a mis ojos no es tan útil, por ejemplo, si el primer comando verificaría si el archivo de salida ya está en el disco, nunca obtendría la respuesta correcta ...
xargs
, es el propio shell el que crea este archivo, porque antes de que se ejecute cualquier comando, el shell redirige todas las entradas, salidas y canalizaciones, de modo que cuandofind
comienza el archivo de salida ya existe. Utilice en su-exec
lugar:find -maxdepth 1 -type f -exec sh -c 'shasum "$@" > sums.sha1' {} +
sh
son necesarias varias invocaciones. Tenga en cuenta que necesita un argumento para$0
antes{}
.tee
ha desaparecido? Lo probé y funciona bien, también suprimí STDOUT con la adición de1>/dev/null
. ¿Hubo algún problema con la respuesta o fue un error?Respuestas:
Puede evitar que el archivo llegue
xargs
usando:Sin embargo, para evitar problemas con el nombre de archivo que tiene espacios en blanco o líneas nuevas o comillas o barras invertidas, usaría:
en lugar.
El
--
objetivo es evitar problemas con los nombres de archivo que comienzan con-
. Sin embargo, no ayudará para un archivo llamado-
. Si lo hubiera usado en-print0
lugar de-printf '%P\0'
, no habría necesitado--
y no habría tenido un problema con el-
archivo.fuente
basename
obtener el nombre de archivo sums.sha1 de la ruta completa dada (esto no se incluyó en la pregunta, pero podría ayudar a otros).Como estás usando
-maxdepth 1
, supongo que no quieres recurrencia. Si es así, simplemente hazlo en el shell:Para omitir directorios, puede hacer:
Si necesita recurrencia y está usando
bash
, haga lo siguiente:Tenga en cuenta que todos estos enfoques tienen la ventaja de trabajar en nombres de archivos arbitrarios, incluidos aquellos con espacios, líneas nuevas o cualquier otra cosa.
fuente
sums.sha1
ya está allí (de una ejecución anterior) su solución lo incorporará.sh
, pero su respuesta podría ayudar a otros.con
zsh
:El globo se expandirá antes de que se realice la redirección, por lo
sums.sha1
que no se incluirá si no estaba allí en primer lugar.D
es incluir archivos de puntos (archivos ocultos) como lofind
haría..
es seleccionar solo archivos regulares (como el suyo-type f
).Para excluir el de
sums.sha1
todos modos en caso de que estuviera allí en primer lugar:Tenga en cuenta que esos ejecutan un comando shasum, por lo que puede terminar viendo un error "Lista de Arg demasiado larga" si la lista es enorme. Para evitar eso:
Recomendaría usar en
./*
lugar de*
evitar posibles problemas con un archivo llamado-
.fuente
Como las otras respuestas ya indicaron, el problema es que el shell se abre y crea el
sums.sha1
archivo, antes de ejecutar su canalización. Puede usar el programasponge
que es parte delmoreutils
paquete de muchas distribuciones. A diferencia de la redirección de shellsponge
, esperará hasta que reciba todo, antes de abrir el archivo. Generalmente se usa cuando desea escribir un archivo que lee en la misma tubería.En su caso se usa así:
fuente
Como alternativa a find / xargs, etc., es posible que desee sha1deep. Sin embargo, probablemente esté en un paquete diferente: en mi caja viene en el paquete md5deep.
Como otros han dicho, el shell crea sums.sha1 incluso antes de que se inicie find. Un truco con
! -name sums.sha1
tofind
funcionará, al igual quefuente