Encuentra todos los archivos donde otros archivos con diferente extensión ya no existen

1

Quiero usar el comando find, para encontrar todos los archivos con una cierta extensión (avi), donde el mismo nombre de archivo con otra extensión (mp4) aún no existe.

considerando estos archivos:

a.avi
a.mp4
c.avi

solo debería dar como resultado que se encuentre el archivo c.avi.

abrazadera
fuente
Qué sistema operativo estás usando?
y31415
@ and31415 ubuntu server
abrazadera el

Respuestas:

1

¿Haría esto?

find . -name '*.avi' -type f -execdir bash -c 'f=("${0%avi}"*);((${#f[@]}==1))' {} \; -print

Trataré de explicar cómo funciona.

Bueno, de hecho es muy fácil: encuentra todos los archivos en el directorio actual de modo que el nombre tenga aviextensión. Para cada uno de estos, digamos que su archivo se X.aviejecuta en el directorio en el que está ( execdir) el comando:

bash -c 'f=("${0%avi}"*);((${#f[@]}==1))' {}

donde {}se reemplaza por el nombre del archivo, en nuestro caso de prueba X.avi. Entonces esto es como

bash -c 'f=("${0%avi}"*);((${#f[@]}==1))' X.avi

En este punto, permítanme enfatizar que esto es 100% seguro con respecto a espacios y otros símbolos divertidos en los nombres de archivos ¿Ahora ves el fragmento que bash ejecutará? Me refiero a este fragmento

f=("${0%avi}"*);((${#f[@]}==1))

Se ejecutará con el parámetro posicional 0 a establecido para nuestro nombre de archivo; en nuestro ejemplo de prueba es X.avi.

La parte se "${0%avi}"expande al nombre de archivo, con el seguimiento avieliminado (por cierto, se garantiza que este nombre de archivo tenga esta extensión en este punto), y la parte "${0%avi}"*se expandirá a todos los archivos en el directorio actual (recuerde, el que contiene el archivo) que tiene el .aviextensión. En nuestro ejemplo de prueba, esto es como:

X.*

Luego construimos una matriz a fpartir de estos y, finalmente, salimos de este bashproceso con éxito si fcontiene solo un elemento (por lo que, muy probablemente, fsolo contiene X.avien nuestro ejemplo de prueba), y de lo contrario falla. Si esto fue un éxito, imprimimos el nombre del archivo.

gniourf_gniourf
fuente
Disculpe, pero si vota negativamente, deje un mensaje. Es muy probable que no haya entendido la profundidad de mi respuesta, y me complacerá darle algunas aclaraciones al respecto. ¡Y hasta podrías aprender algo en el proceso! :D
gniourf_gniourf
1
No voté en contra, pero estoy tentado a hacerlo. Dudo que esto funcione, pero no tengo acceso a un sistema * nix en este momento, así que no puedo probarlo. (¿Lo ha probado?) Explique cómo / por qué cree que esto funciona y prepárese para aprender algo usted mismo cuando alguien venga y le diga por qué no funciona.
Scott
@ Scott, regrese cuando tenga un sistema * nix disponible, y tendremos una pequeña charla. Mientras tanto, siéntase libre de votar negativamente, pero si lo hace, dedique 2 minutos a aclarar sus dudas de que no funciona, conviértalo en una certeza con un razonamiento sólido (si puede, jaja).
gniourf_gniourf
Tal vez no te sientas cómodo con las expansiones de parámetros bash (hey, después de todo, estamos en SU, no como si estuviéramos en un sitio con muchachos expertos); Si ese es el caso, elimine su comentario. Déjame decirte que creo que es así, porque cualquiera que sepa bash al menos un poco entenderá este fragmento trivial.
gniourf_gniourf
1

Una solución con 2 exec () s:

encontrar . -name '* .avi' -print | \
  perl -n -e '$ x = $ _; $ x = ~ s / \. avi \ s * $ /. mp4 /; (-e $ x) || impresión'

Pasos:

  1. estos son los droides que estás buscando
  2. para cada línea / archivo de entrada, pruebe el archivo .mp4 correspondiente y repita el nombre de archivo .avi si no se encuentra
    1. copie la línea de entrada a $ x
    2. sustituya .mp4 por .avi en $ x (pero solo al final de la línea)
    3. si existe el archivo .mp4 correspondiente, hemos terminado con esta línea; de lo contrario, imprima la línea de entrada
Scott Leadley
fuente
0

Otra opción: buscar todos .mp4y .aviarchivos, luego eliminar de la lista cualquier archivo para el que existan ambas extensiones, y luego eliminar los archivos .mp4 restantes:

find . -name '*.avi' -or -name '*.mp4' |
rev | sort -t. -k2 -k1,1 | uniq -s3 -u | grep -v '^4pm' | rev | sort

(Se supone que ningún archivo tiene una nueva línea en su nombre).

rici
fuente
-1

Una solución con 3 exec () s:

find . -name '*.avi' -print | \
  sed 's/\(.*\)\.avi$/if [ ! -f "\1.mp4" ]; then echo "\1.avi"; fi/' | \
  sh

Pasos:

  1. estos son los droides que estás buscando
  2. quitar la extensión de archivo .avi; escriba una secuencia de comandos sh que compruebe el archivo .mp4 correspondiente y muestre el nombre de archivo .avi si no se encuentra
  3. evaluar los comandos sh
Scott Leadley
fuente
Ojalá pudiera touch '" ]; then rm -rf /; [ ! -f ".avi'. Sorpresa :D.
gniourf_gniourf
Argumentos a favor / en contra de esta tubería. Pro: muy simple, muy fácil de adaptar. Con: esta tubería podría hacer cosas malas en circunstancias patológicas (como en el ejemplo de gniourf_gniourf). Por lo tanto, ejecutar con privilegios de root sin más controles sería una mala idea.
Scott Leadley