3 votos

¿Puede AppleScript obtener el contenido de las carpetas con exclusión de la extensión del archivo?

Buscando una manera en AppleScript para obtener el contenido de un directorio con una exclusión para analizar. Sé cómo hacer esto usando find en un bucle for con el comando:

find . -not -name "*.bat"

pero tengo curiosidad por saber si hay una Sólo AppleScript para obtener el contenido de una carpeta sin la extensión del archivo .bat .

He creado un directorio ficticio en mi escritorio, he añadido varios archivos y he probado:

tell application "Finder"
    set theFiles to get every item of (entire contents of folder (choose folder)) whose kind != ".bat"
    reveal theFiles
end tell

el .bat se resaltan los archivos. Utilizando does not contain compila pero da error a:

Error:

No se pueden conseguir todos los artículos de verdad.

Código:

tell application "Finder"
    set theFiles to get every item of (entire contents of folder (choose folder) does not contain ".bat")
    reveal theFiles
end tell

Intentando otra aproximación obtengo un error de:

Error:

El buscador tiene un error: Tipo de objeto desconocido.

Código:

tell application "Finder"
    set theFiles to get every item of (entire contents of folder (choose folder)) whose type != {"public.bat"}
    reveal theFiles
end tell

Si trato de modificar el enfoque sólo puedo obtener un resultado sólido si acoto el nombre de un archivo bat usando:

Código:

tell application "Finder"
    set theFiles to get (every file of folder (choose folder) whose name is not in {"foobar.bat"})
    reveal theFiles
end tell

En AppleScript puro, ¿hay alguna forma de obtener el contenido de un directorio con una exclusión por tipo de archivo? Posiblemente me gustaría encadenar la exclusión para múltiples tipos de archivo.

2voto

Blamdarot Puntos 1517

Prueba esto:

tell application "Finder"
    set theFiles to files in folder (choose folder) whose name does not end with ".bat"
    reveal theFiles
end tell

0 votos

Voy a añadir una advertencia de que, si bien esto debería funcionar, y es lo que el OP pidió, en mi experiencia ejecutar do shell script será mucho más rápido en un directorio con muchos archivos. Ni idea de por qué.

1 votos

Utilice Eventos del sistema en lugar de Buscador para hacer la búsqueda de archivos, y luego Buscador para hacer la revelación. O bien, si desea utilizar simplemente Buscador , pídale que le devuelva un lista de alias que también es más rápido.

2voto

qarma Puntos 71

Buscador

A continuación se presentan algunas formas diferentes de filtrar por extensión de archivo, con una breve descripción de sus ventajas. A modo de ilustración, he puesto Buscador las operaciones realizadas sobre un Buscador ventana (mi Fotos ), que tiene muchos jpegs que sirven como una buena muestra con la que probar los filtros de exclusión.

tell application "Finder" to select (every file in the ¬
    front Finder window whose name does not end with ".jpg")

La segunda vez que se realizó, se tardó 14 segundos, con el fin de proporcionar una línea de base para las comparaciones aproximadas.

El simple hecho de coaccionar el resultado a un alias list aceleró sistemáticamente el tiempo de ejecución a 8 segundos (casi el doble de rápido):

tell application "Finder" to select ((every file in the ¬
    front Finder window whose name does not end with ".jpg") as alias list)

Sorprendentemente para mí, filtrar por name extension no parecía afectar a los tiempos de rendimiento en comparación con el uso del name lo que podría sugerir que ambos realizan comparaciones de cadenas equivalentes bajo el capó:

tell application "Finder" to select ((every file in the ¬
    front Finder window whose name extension is not "jpg") as alias list)

No obstante, yo elegiría preferentemente filtrar por name extension como una cuestión de elección personal, porque es una sintaxis más limpia.

Una de las ventajas de Buscador es que podemos condensar varios filtros en una sola expresión inclusiva que esencialmente forma una lista de predicados:

tell application "Finder" to select ((every file in the ¬
    front Finder window whose name extension is not in ¬
    ["jpg", "png"]) as alias list)

y esto fue igual de rápido para dos extensiones que para una, y luego otra vez para cuatro:

tell application "Finder" to select ((every file in the ¬
    front Finder window whose name extension is not in ¬
    ["jpg", "png", "mov", "mp4"]) as alias list)

Filtrado por el name no puede hacerse con múltiples extensiones de esta manera, por lo que debe hacerse con cláusulas separadas para cada extensión que se desee excluir:

tell application "Finder" to select ((every file in the front Finder window whose ¬
    name does not end with "jpg" and ¬
    name does not end with "png" and ¬
    name does not end with "mp4" and ¬
    name does not end with "mov") as alias list)

Eventos del sistema

Eventos del sistema está mucho más equipado para manejar el procesamiento y filtrado de archivos que Buscador Lo cual es algo contraintuitivo. También impide Buscador que se bloquea durante la operación.

No se puede utilizar una lista de predicados como se puede hacer con Buscador Así que tenemos que conformarnos con las expresiones más largas:

tell application "System Events" to get path of every file in the ¬
    pictures folder whose visible = true and ¬
    name extension is not "jpg" and ¬
    name extension is not "png" and ¬
    name extension is not "mp4" and ¬
    name extension is not "mov"

tell application "Finder" to select the result

Pero el hecho de que esta operación lleve aproximadamente cero segundos hace que merezca la pena. Obsérvese aquí que he preguntado Eventos del sistema para devolver el path a estos elementos, simplemente para poder pasar el resultado a Buscador y hacer que los seleccione como antes (así también se puede usar reveal después de un Eventos del sistema llamada).


Objetivo-C

Si necesita buscar en carpetas enormes o en una lista anidada de carpetas, no tenga la tentación de utilizar El buscador entire contents propiedad, o te hará llorar. Utilice AppleScriptObjC, que realiza búsquedas profundas en árboles de carpetas con tiempos de rendimiento más rápidos que Eventos del sistema y la cáscara. Tiene el coste de unos gastos generales ligeramente superiores a los de Eventos del sistema / Buscador pero probablemente sea comparable a la de llamar a un shell script.

En primer lugar, es mejor definir algunos manejadores que se encarguen de la búsqueda y el filtrado de archivos:

use framework "Foundation"
use scripting additions

property this : a reference to current application
property NSDirectoryEnumerationSkipsHiddenFiles : a reference to 4
property NSDirectoryEnumerationSkipsPackageDescendants : a reference to 2
property NSFileManager : a reference to NSFileManager of this
property NSMutableSet : a reference to NSMutableSet of this
property NSPredicate : a reference to NSPredicate of this
property NSSet : a reference to NSSet of this
property NSString : a reference to NSString of this
property NSURL : a reference to NSURL of this

on filesInDirectory:fp excludingExtensions:exts
    local fp, exts

    set all to contentsOfDirectory at fp
    set |*fs| to all's filteredArrayUsingPredicate:(NSPredicate's ¬
        predicateWithFormat:("pathExtension IN %@") ¬
            argumentArray:[exts])

    set fs to NSMutableSet's setWithArray:all
    fs's minusSet:(NSSet's setWithArray:|*fs|)
    fs's allObjects() as list
end filesInDirectory:excludingExtensions:

on contentsOfDirectory at fp
    local fp

    set FileManager to NSFileManager's defaultManager()

    set fs to FileManager's enumeratorAtURL:(NSURL's ¬
        fileURLWithPath:((NSString's stringWithString:fp)'s ¬
            stringByStandardizingPath())) ¬
        includingPropertiesForKeys:[] ¬
        options:(NSDirectoryEnumerationSkipsHiddenFiles + ¬
        NSDirectoryEnumerationSkipsPackageDescendants) ¬
        errorHandler:(missing value)

    fs's allObjects()
end contentsOfDirectory

Entonces, puedes realizar una llamada como esta:

get my filesInDirectory:"~/Pictures" excludingExtensions:["jpg", "JPG", ""]
-- tell application "Finder" to reveal the result

Tenga en cuenta que Objective-C realizará búsquedas que distingan entre mayúsculas y minúsculas, por lo que es prudente incluir las extensiones de los archivos a excluir tanto en mayúsculas como en minúsculas. La cadena vacía excluye las carpetas (excepto cuando el nombre de la carpeta contiene un punto).

Objective-C realizó una enumeración profunda de mi Fotos filtrando todos los jpegs para devolver una lista de 643 archivos anidados en ese directorio, y lo hizo en aproximadamente cero segundos . Tampoco Buscador ni Eventos del sistema puede coincidir con este tiempo ( Buscador no responde después de un tiempo, y haciendo una búsqueda profunda con Eventos del sistema requiere iterar manualmente a través de las carpetas hijas, y decidir cómo manejar la lista anidada que devuelve, pero lo hace en unos impresionantes 4 segundos). El intérprete de comandos es igual de rápido para este número de archivos, pero estoy bastante seguro de lo que he leído que Objective-C superará al intérprete de comandos find para grandes volúmenes de archivos.

Verás que he comentado el Buscador 's reveal comando: pedir Buscador para revelar 643 archivos en diferentes carpetas fue... um... desagradable. No lo recomiendo.


Conclusión:

Utilice Eventos del sistema para realizar búsquedas de archivos y, opcionalmente, recuperar las rutas de los mismos, que pueden utilizarse para cualquier operación que se desee Buscador para realizar posteriormente sobre ellos.

Si, por alguna razón, necesita utilizar Buscador para realizar la búsqueda de archivos, siempre coacciona a alias list para obtener beneficios de rendimiento y una clase de elemento que es universalmente mucho más fácil de manejar después.

Para estructuras de carpetas grandes o anidadas, utilice Objective-C.

AppleAyuda.com

AppleAyuda es una comunidad de usuarios de los productos de Apple en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X