¿Puede AppleScript obtener el contenido de la carpeta con la exclusión de la extensión de archivo?

2

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

find . -not -name "*.bat"

pero tengo curiosidad por saber si existe un enfoque AppleScript only para obtener el contenido de una carpeta sin la extensión de archivo .bat .

He construido un directorio ficticio en mi escritorio, agregué varios archivos y probé:

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

los archivos .bat están resaltados. El uso de does not contain compila, pero genera errores en:

error:

  

No se pueden obtener todos los elementos 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 otro enfoque me sale un error de:

error:

  

El buscador obtuvo 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 intento modificar el enfoque, solo puedo obtener un resultado sólido si reduzco el nombre de un archivo bat mediante:

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 una forma de obtener el contenido de un directorio con una exclusión para el tipo de archivo? Posiblemente me gustaría encadenar la exclusión para múltiples tipos de archivos.

    
pregunta ʀ2ᴅ2 15.11.2018 - 19:43

2 respuestas

2

Prueba esto:

tell application "Finder"
    set theFiles to files in folder (choose folder) whose name does not end with ".bat"
    reveal theFiles
end tell
    
respondido por el mbamac 15.11.2018 - 23:04
1

Buscador

Aquí hay algunas formas diferentes de filtrar por extensión de archivo, con una breve descripción de sus beneficios. Para fines de ilustración, he tenido operaciones de Finder en una ventana abierta de Finder (mi carpeta Pictures ), que tiene muchos archivos JPEG en. Es una buena muestra contra la cual 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")

Esto tomó 14 segundos en su segunda ejecución, para proporcionar una línea de base para comparaciones aproximadas.

El simple acto de coaccionar el resultado a un alias list aceleró el tiempo de rendimiento 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)

Para mí, sorprendentemente, el filtrado por name extension no pareció afectar los tiempos de rendimiento en comparación con el uso de la propiedad name , posiblemente sugiriendo que ambos están realizando 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, preferiría filtrar por name extension como una cuestión personal, porque es una sintaxis más clara.

Uno de los beneficios de Finder es que podemos condensar múltiples filtros en una 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 tan 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)

El filtrado por la propiedad name no se puede hacer con múltiples extensiones de esta manera, por lo que se debe hacer con cláusulas separadas para cada extensión que 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

System Events está mucho más equipado para manejar el procesamiento y filtrado de archivos que Finder , que es algo contraintuitivo. También evita que Finder se bloquee durante la operación.

No puedes usar una lista de predicados como puedes con Finder , 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 tome aproximadamente cero segundos hace que valga la pena. Tenga en cuenta que le pedí a Eventos del sistema que devolviera path a estos elementos, simplemente para poder pasar el resultado a Finder y hacer que los seleccione como antes (esto También es cómo puede usar reveal después de una llamada de Eventos del sistema ).

Objective-C

Si necesitas buscar en carpetas grandes o en una lista anidada de carpetas, no te sientas tentado a usar la propiedad Finder's entire contents , o te hará llorar. Use AppleScriptObjC, que realiza búsquedas profundas de árboles de carpetas con tiempos de rendimiento más rápidos que Eventos del sistema y shell. Tiene un costo de un poco más de sobrecarga en comparación con Eventos del sistema / Finder , pero probablemente comparable al de llamar a un script de shell.

Primero, es mejor definir algunos manejadores para 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

Luego, 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 distinguen entre mayúsculas y minúsculas, por lo que es prudente incluir las extensiones de archivo que se excluirán tanto en formato de mayúsculas como de 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 carpeta Imágenes filtrando todos los archivos JPEG para devolver una lista de 643 archivos anidados dentro de ese directorio, y lo hizo en aproximadamente cero segundos . Ni Finder ni System Events pueden coincidir esta vez ( Finder no responderá después de un tiempo, y realizar una búsqueda profunda con System Los eventos requieren una iteración manual a través de carpetas secundarias, y decidir cómo manejar la lista anidada que devuelve, pero lo hace en unos impresionantes 4 segundos. El shell es igual de rápido para este número de archivos, pero confío bastante en lo que he leído que Objective-C ejecutará el comando find del shell para grandes volúmenes de archivos.

Verás. Comenté el comando reveal del Finder : pedirle a Finder que revelara 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 rutas de archivos, que pueden utilizarse para cualquier operación que desee que Finder realice posteriormente sobre ellas.

② Si, por alguna razón, necesita usar Finder para realizar la búsqueda de archivos, siempre coaccione con alias list para obtener beneficios de rendimiento y una clase de elemento eso es mucho más fácil de manejar más tarde.

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

    
respondido por el CJK 16.11.2018 - 21:31

Lea otras preguntas en las etiquetas