Sí, estoy ordenando mi música. Tengo todo arreglado maravillosamente en el siguiente mantra: /Artist/Album/Track - Artist - Title.ext
y si existe uno, la cubierta se asienta /Artist/Album/cover.(jpg|png)
.
Quiero escanear todos los directorios de segundo nivel y encontrar los que no tienen una tapa. Por segundo nivel, quiero decir que no me importa si /Britney Spears/
no tiene una cover.jpg, pero me importaría si /Britney Spears/In The Zone/
no tuviera una.
No se preocupe por la descarga de la portada (ese es un proyecto divertido para mí mañana). Solo me importa la gloriosa bash-fuiness sobre un find
ejemplo inverso .
Respuestas:
Caso 1: conoce el nombre exacto del archivo que debe buscar
Use
find
contest -e your_file
para verificar si existe un archivo. Por ejemplo, busca directorios que no tienencover.jpg
en ellos:Sin embargo, es sensible a mayúsculas y minúsculas.
Caso 2: quieres ser más flexible
No está seguro del caso, y la extensión podría ser
jPg
,png
...Explicación:
sh
para cada directorio, ya que no se pueden establecer tuberías al usarfind
ls -1 "{}"
genera solo los nombres de archivo del directorio quefind
está atravesando actualmenteegrep
(en lugar degrep
) usa expresiones regulares extendidas;-i
hace que el caso de búsqueda sea insensible,-q
hace que omita cualquier salida"^cover\.(jpg|png)$"
Es el patrón de búsqueda. En este ejemplo, coincidecOver.png
, por ejemplo ,Cover.JPG
ocover.png
. El.
debe escapar, de lo contrario significa que coincide con cualquier personaje.^
marca el inicio de la línea,$
su finalOtros ejemplos de patrones de búsqueda para egrep :
Sustituya la
egrep -i -q "^cover\.(jpg|png)$"
parte con:egrep -i -q "cover\.(jpg|png)$"
: También coincidecd_cover.png
,album_cover.JPG
...egrep -q "^cover\.(jpg|png)$"
: Coincidecover.png
,cover.jpg
pero NOCover.jpg
(la distinción entre mayúsculas y minúsculas no está desactivada)egrep -iq "^(cover|front)\.jpg$"
: coincidefront.jpg
, por ejemplo ,Cover.JPG
pero noCover.PNG
Para obtener más información sobre esto, consulte Expresiones regulares .
fuente
test
.-exec bash -c '[[ -n $(find "{}" -iname "cover.*") ]]' \;
pero eso es bastante sucio en términos de optimización. Sin embargo, funciona.test
una gran cantidad de-o EXPRESSION
consultas OR ... por ejemplo: lotest -e "{}/cover.jpg" -o -e "{}/cover.png"
que es mejor que hacer una búsqueda completa, pero aún distingue entre mayúsculas y minúsculas.$
en el nombre del directorio (Ke $ ha, por ejemplo).Simple, transpira. A continuación se obtiene una lista de directorios con la portada y se compara con una lista de todos los directorios de segundo nivel. Las líneas que aparecen en ambos "archivos" se suprimen, dejando una lista de directorios que necesitan cubiertas.
¡Hurra!
Notas:
comm
Los argumentos son los siguientes:-1
suprimir líneas exclusivas del archivo1-2
suprimir líneas exclusivas de file2-3
suprimir líneas que aparecen en ambos archivoscomm
solo toma archivos, de ahí el<(...)
método de entrada kooky . Esto canaliza el contenido a través de un archivo real [temporal].comm
necesita una entrada ordenada o no funciona yfind
de ninguna manera garantiza un pedido. También debe ser único. La primerafind
operación podría encontrar varios archivos, porcover.*
lo que podría haber entradas duplicadas.sort -u
rápidamente despeina a esos a uno. El segundo hallazgo siempre será único.dirname
es una herramienta útil para obtener el directorio de un archivo sin recurrir ased
(et al).find
ycomm
ambos son un poco desordenados con su salida. La finalsed
está ahí para limpiar las cosas para que te quedesArtist/Album
. Esto puede o no ser deseable para usted.fuente
find
posiblemente se pueda simplificarfind ~/Music/ -iname 'cover.*' -printf '%h\n'
, evitando la necesidad de hacerlodirname
. aunquedirname
es útil en otros lugares.Esto es mucho mejor para resolver con globbing que con find.
Ahora suponga que no tiene archivos perdidos en esta bonita estructura. El directorio actual contiene solo subdirectorios de artistas, y esos contienen solo subdirectorios de álbumes. Entonces podemos hacer algo como esto:
La
<(...)
sintaxis es la sustitución del proceso Bash: le permite usar un comando en lugar de un argumento de archivo. Le permite tratar la salida de un comando como un archivo. Entonces podemos ejecutar dos programas y tomar su diff, sin guardar su salida en archivos temporales. Eldiff
programa cree que está trabajando con dos archivos, pero en realidad está leyendo desde dos canales.El comando que produce la entrada a mano derecha
diff
,printf "%s\n" */*
, solo muestra los directorios del álbum. El comando de la mano izquierda recorre las*.cover
rutas e imprime sus nombres de directorio.Prueba de funcionamiento:
Ajá, los directorios
a/b
yfoo/bar
no tienencover.jpg
.Hay algunos casos de esquina rota, por ejemplo, de forma predeterminada se
*
expande a sí mismo si no coincide con nada. Esto se puede solucionar con Bash'sset -o nullglob
.fuente
comm
sería más limpio quediff
?comm -3 <(printf "%s\n" */*/cover* | sed -r 's/\/[^\/]+$//' | sort -u) <(printf "%s\n" */*)
parece un compromiso razonable sin ninguna dediff
las pelusas. Sin embargo, es un poco más lento que mi doble hallazgo.Mostrará todos los directorios que no tengan archivos txt en ellos.
fuente