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 ~/testcon archivos f1y 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 -pflag 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 cuandofindcomienza el archivo de salida ya existe. Utilice en su-execlugar:find -maxdepth 1 -type f -exec sh -c 'shasum "$@" > sums.sha1' {} +shson necesarias varias invocaciones. Tenga en cuenta que necesita un argumento para$0antes{}.teeha 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
xargsusando: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-print0lugar de-printf '%P\0', no habría necesitado--y no habría tenido un problema con el-archivo.fuente
basenameobtener 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.sha1ya 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.sha1que no se incluirá si no estaba allí en primer lugar.Des incluir archivos de puntos (archivos ocultos) como lofindharía..es seleccionar solo archivos regulares (como el suyo-type f).Para excluir el de
sums.sha1todos 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.sha1archivo, antes de ejecutar su canalización. Puede usar el programaspongeque es parte delmoreutilspaquete 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.sha1tofindfuncionará, al igual quefuente