Escribí un script bash hoy durante mi pausa para el almuerzo que busca archivos sin extensión en un directorio y les agrega una extensión de archivo.
El script es relativamente largo porque agregué un montón de indicadores y cosas como la selección de directorio y si copiar o sobrescribir el archivo, pero el meollo de su funcionalidad se puede replicar simplemente con esto:
#recursively find files in current directory that have no extension
for i in $(find . -type f ! -name "*.*"); do
#guess that extension using file
extfile=$(file --extension --brief $i)
#select the first extension in the event file spits something weird (e.g. jpeg/jpe/jfif)
extawk=$(echo $extfile | awk -F/ '{print $1}')
#copy the file to a file appended with the extension guessed from the former commands
cp -av $i $i.$extawk
done
Es un poco más ordenado en mi script actual; solo quería dividir los comandos aquí para poder comentar por qué estaba haciendo las cosas.
Mi pregunta: Usar find
en combinación con file
la forma que he elegido probablemente no sea la forma más infalible de hacerlo: ¿cuál es elmejor¿Manera de adivinar y agregar extensiones de forma recursiva para un grupo masivo de diversos tipos de archivos entre varios directorios?
Respuesta1
for x in $(find …)
falla connombres de archivos que contienen espacios en blanco (común) o caracteres comodín (algo poco común). Nunca analice la salida de find
. Usar -exec
.
Zsh'szmv
es conveniente para cambios de nombre masivos.
Construyamos un comando zmv que haga lo que usted quiere. Primero, construyamos el patrón de búsqueda:
autoload zmv
zmv -C -o -a -n -Q '(*/)#^*.*(.)' …
-C
hace que los archivos se copien en lugar de moverse.-o -a
pasa-a
acp
.-n
significa no actuar, simplemente imprimir lo que se haría. Quítelo una vez que esté satisfecho. Sustitúyelo por-v
si quieres actuar pero también imprime lo que se está haciendo.-Q
permiteclasificatorios globalesen el patrón.(*/)#
coincide con cero o más directorios. Utiliza el#
operador global(extended_glob
siempre está habilitado en zmv).^*.*
utiliza el^
operador global para hacer coincidir archivos sin a.
en su nombre.(.)
es un calificador global que restringe las coincidencias a archivos normales.…
será reemplazado por el texto de reemplazo. Esto puede usarse$f
para referirse al nombre original.
zmv
calcula todos los nombres de reemplazo antes de realizar cualquier reemplazo y se quejará si ya existe algún nombre de reemplazo o si hay conflictos. Se omitirán los archivos cuyo nombre de reemplazo sea idéntico al original.
Ahora construyamos el texto de reemplazo. Usaremos muchoexpansión de parámetroscaracterísticas.
- Pregunta
file
por la extensión:$(file --extension --brief -- $f)
- Anteponga a
.
, en preparación para el reemplazo:$(echo -n .; file --extension --brief -- $f)
(Esto también se podría hacer con la expansión de parámetros:${:-.$(…)}
.) - Si hay varias extensiones sugeridas (separadas por barras), conserve solo la primera:
${$(echo -n .; file --extension --brief -- $f)%%/*}
- Si la extensión sugerida está vacía o
???
, abandone (reemplace.
o.???
por una cadena vacía):${${$(echo -n .; file --extension --brief -- $f)%%/*}:#.(|\?\?\?)}
- Agregue la extensión agregada a
$f
(el nombre original). Si lo que estamos agregando está vacío, el archivo quedará intacto.
El comando resultante:
zmv -C -o -a -n -Q '(*/)#^*.*(.)' '$f${${$(echo -n .; file --extension --brief -- $f)%%/*}:#.(|\?\?\?)}'
Esto es un poco críptico y es posible que prefieras poner el código para generar el reemplazo en una función y uso zmv … '$(add_extension $f)'
.
Respuesta2
Creo que la forma más efectiva es comparar los tipos mime del archivo con la base de datos ubicada en /usr/share/mime/globs
.
- globosen Linux sonextensión de archivo. Ejemplo dado, salida dearchivo globs
application/x-mswinurl:*.url
text/x-mrml:*.mrl
text/x-erlang:*.erl
audio/x-pn-audibleaudio:*.aa
application/x-bzip-compressed-tar:*.tbz2
application/x-netshow-channel:*.nsc
application/x-hdf:*.h4
application/pgp-keys:*.key
text/x-idl:*.idl
text/x-chdr:*.h
application/vnd.ms-powerpoint.presentation.macroEnabled.12:*.pptm
application/vnd.ms-powerpoint.presentation.macroEnabled.12:*.pptm
application/vnd.visio:*.vsd
application/x-hdf:*.h5
video/vnd.mpegurl:*.m4u
- después de describir el tipo de ejemplo -->
text/x-erlang
, le dice a Linux que identifique todos los archivos*.
comoerlangcon extensión.erl
[glob], por eso -->*.erl
- Puedes agregar tus propias extensiones para que se tengan en cuenta en el
/etc/magic
archivo.
entonces ejecutando el comando:
mimetype -bM file
b
Argumento para mostrartetype-app/extension
(breve)M
argumento significamagiaes la forma en que Linux verifica el archivo en código de bytes, hexadecimal, binario para verificar que los archivos son realmente lo que dicen ser.tipo de Mimicano devuelve
/jpg/png/webp
solo devuelve un tipo, y es más corto quefile --mime-type file
Devoluciones:
image/webp
pensamientos finales
mimetype
funciona mejor conarchivos binarioscomo archivos PDF, imágenes y vídeos. Esto se debe a que puede verificar el binario, en cambio, text plain
es solo eso, y necesitas identificarte con algo, y esto es más complicado, es por eso que los editores de texto pueden reconocer diferentes lenguajes de programación, necesita la ayuda del usuario y un lenguaje de servidor para cada lenguaje de programación.
para recursividad, creoárbolestá bien:
tree -FIi '*.*' | grep -v /$
- El argumento
F
es agregar/
[barra] a los directorios, ejemplo,folder
→folder/
- El argumento
I
es seleccionar el opuesto del patrón*.*
[esto significa seleccionar todos los archivos con extensión], por lo que lo opuesto no es extensión - El argumento
i
es eliminar espacios de la salida del árbol. grep -v
es seleccionar revertir, es por eso que agrega el/
argumento -F aárbolcomando al principio, para que pueda eliminar directorios y obtener solo archivos, con/$
.
Mira más aquítipos de mimo