Eliminar ruta de salida del comando find

29

Tengo una secuencia de comandos bash para implementar código de un entorno beta a un entorno de producción, pero actualmente tengo que agregar la lista de archivos a un archivo txt de forma manual y, a veces, me faltan algunos. Básicamente mi script de implementación cat / loops copiando los archivos. (exportaciones / importaciones db también, pero eso no es relevante ... jajaja)

De todos modos, me gustaría usar el findcomando para generar una lista de archivos modificados en los últimos 14 días. El problema es que necesito quitar la ruta ./para que el script de implementación funcione.

Aquí hay un ejemplo del uso del comando find:

encontrar . -type f -mtime -14> deploy.txt

Aquí está la línea que gatos deploy.txten mi script de implementación:

for i in `cat deploy.txt`; do cp -i /home/user/beta/public_html/$i /home/user/public_html/$i; done

¿Alguna idea de cómo lograr esto usando scripts de bash?

¡Gracias!

Mikey1980
fuente
3
¿Hay alguna razón por la que no puedes usar rsync para esto? Parece que está intentando reinventar la rueda y convertirla en un triángulo.
ThatGraemeGuy
Sin embargo, antes de la implementación, se revisa el deploy.txt y se elimina todo lo que necesita reparación
Mikey1980
1
¿Quizás ejecute rsync en --dry-runmodo y envíe eso a un archivo para su revisión?
Zoredache

Respuestas:

36

Puede usar la -printfopción de línea de comando con %fpara imprimir solo el nombre del archivo sin ninguna información de directorio

find . -type f -mtime -14 -printf '%f\n' > deploy.txt

o puede usar sed para simplemente eliminar el ./

find . -type f -mtime -14 | sed 's|^./||' >deploy.txt
Iain
fuente
Creo que tienes que escapar del /..
EEAA
55
No cuando lo usas |como delimitador.
user9517 es compatible con GoFundMonica el
3
El uso %feliminará todos los directorios, no solo ./. Esto interrumpirá su secuencia de comandos de implementación si alguno de los archivos devueltos findse encuentra en subdirectorios.
James Sneeringer
2
@Iain Sin embargo, debes escapar del .. Y quizás sea mejor usar un ancla de inicio de línea:s|^\./||
James O'Gorman el
12
Usar en %Plugar de %f. Esto simplemente cortó la ruta dada en la línea de comando.
Verdaderamente
12

El ./debe ser inofensivo. La mayoría de los programas serán tratados /foo/bary /foo/./barcomo equivalentes. Me doy cuenta de que no se ve muy bien, pero en base a lo que has publicado, no veo ninguna razón por la que pueda fallar tu script.

Si realmente quieres quitártelo, sedes probablemente la forma más limpia:

find . -type d -mtime 14 | sed -e 's,^\./,,' > deploy.txt

Si está en un sistema con GNU find (por ejemplo, la mayoría de los sistemas Linux), puede hacerlo de una vez con find -printf:

find . -type d -mtime 14 -printf "%P\n" > deploy.txt

Las %Pdeclaraciones de la ruta completa de cada archivo encontrado, menos la ruta especificada en la línea de comandos, hasta e incluyendo la primera barra. Esto preservará cualquier subdirectorio en su estructura de directorios.

James Sneeringer
fuente
1
El ./prefijo es en realidad una característica; sin él, la salida de la tubería a otros comandos no funcionará correctamente, por ejemplo, para los nombres de archivo que comienzan con un guión.
tripleee
1
@tripleee: entiendo la utilidad de esto, pero OP preguntó específicamente cómo quitarlo porque estaba causando problemas para su script de implementación. Claro, puede haber mejores formas de hacer lo que necesita hacer, pero eso es un agujero de conejo mucho más allá del alcance de lo que se le pidió.
James Sneeringer
7

¿Por qué necesitas quitarte el ./? Es válido tener en un camino. Asi que

cp -i dir1/./somefile dir2/./somefile

está bien!

Pero si desea quitar el nombre del directorio en find, puede usar el %Pargumento para -printf.

man find (1) dice:

         %P     File's name with the name of the  command  line  argument
                 under which it was found removed.

Un ejemplo

$ find other -maxdepth 1
other
other/CVS
other/bin
other/lib
other/doc
other/gdbinit
$ find other -maxdepth 1 -printf "%P\n"

CVS
bin
lib
doc
gdbinit

¡Cuidado con la primera línea vacía! Si quieres evitarlo usa-mindepth 1

$ find other -mindepth 1 -maxdepth 1 -printf "%P\n"
CVS
bin
lib
doc
gdbinit
Verdad
fuente
3

Bueno, tienes algunas opciones. Puede usar la -printfopción en buscar para imprimir solo el nombre del archivo, o puede usar una herramienta como sed para simplemente quitar el ./.

# simply print out the filename, will break if you have sub-directories.
find . -mtime -14 -printf '%f\n'

# strip a leading ./
find .  -mtime -14 | sed -e 's/^\.\///'
Zoredache
fuente
¿Me puede dar un ejemplo de su uso? Lo siento, Linux no es realmente mi forté
Mikey1980
2
Mira de nuevo, hay ejemplos.
Zoredache
De acuerdo: solo pruébalo, no dañarás nada ejecutando una combinación de find y sed.
EEAA
3

La solución "find -printf" no funcionará en FreeBSD porque find no tiene esa opción. En este caso, AWK puede ayudar. Devuelve un apellido ($ NF), por lo que puede funcionar en cualquier profundidad.

find /usr/local/etc/rc.d -type f | awk -F/ '{print $NF}'

PD: tomado del libro "Programación shell Linux y Unix" de D.Tansley

usuario221341
fuente
2

Una solución rápida, si entiendo correctamente la pregunta, es usar cuten la salida del findcomando:

$> find . -type f -mtime -14 | cut -b 3- > deploy.txt

Esto eliminará los primeros caracteres de cada línea del resultado (en su caso ./). Probablemente no sea la mejor solución, pero funciona en su escenario.

Alessandro Dotti Contra
fuente
1

sed es perfecto para este tipo de cosas

$ find . -type f -mtime -14 find . | sed 's/^\.\///' > deploy.txt
EEAA
fuente
1

No sé de qué tipo de nombres de archivo estamos hablando, pero cualquier cosa con espacios o líneas nuevas pone en riesgo la mayoría de las soluciones.

Mi sugerencia sería usar la expansión de parámetros de shell para eliminar los caracteres de cada nombre de archivo:

find . -mtime -14 -exec sh -c 'printf "${0#./}\n"' {} \; >deploy.txt

Si realmente te gustan las tuberías, puedes usar un delimitador "seguro", como un nulo, con xargs para recibir cada nombre de archivo:

find . -mtime -14 -print0 | xargs -0 -n 1 sh -c 'printf "${0#./}\n"' >deploy.txt

Recuerde que el resultado de esto NO está delimitado por un valor nulo, por lo que si bien puede ser suficiente para una comprobación del globo ocular, ninguna de estas soluciones produce un archivo deploy.txt que sea seguro de usar para la automatización, a menos que esté muy seguro de su fuente nombres de archivo

ghoti
fuente