3 votos

Copiar y aplanar el contenido del directorio con zsh

Tengo un árbol de directorios, donde cada subdirectorio contiene varios tipos de archivos diferentes, quiero copiar un tipo de archivo en particular de cada uno de los subdirectorios, pero necesito aplanar los resultados, para que todos terminen en un solo directorio - sólo copiando los archivos recién agregados y preservando los permisos He estado usando cp bajo zsh, con la siguiente línea de comandos

cp -np **/*.ftype ../destination

Lo que ha funcionado brillantemente hasta ahora. Sin embargo, he llegado a un límite, no estoy seguro de si es el número de directorios en el directorio de origen (actualmente 217) o el número total de directorios / archivos deseados, (en algún lugar entre 2672 y 2690), pero de repente estoy recibiendo el error argument list too long: cp

Esperaba utilizar algo como cp -np [A-Ma-m]**/*.ftype ../destination y dividir el trabajo en partes, pero consigo no matches found: [A-Ma-m]**/*.ftype aunque sé que tengo directorios que comienzan con estos rangos.

También he probado

find Base_dir/ -iname '*.ftype' | xargs -J% cp -np % ../destination 

pero parece que rompe los directorios en cada punto en el que hay un carácter de espacio en el nombre, por lo que no copia nada.

Seguro que estoy haciendo alguna tontería mal, pero cualquier ayuda se agradecería.

3voto

La longitud de una línea de comandos en un shell está limitada, probablemente a algo así como 65536 caracteres. Así que si tu patrón se expande a más caracteres que eso, obtendrás el error "lista de argumentos demasiado larga" que mencionas.

En estos casos, find es el mejor enfoque (entonces también funcionará para los usuarios de otros shells). La copia se puede realizar con uno de los siguientes métodos

find base_dir/ -iname '*.ftype' -print0 | xargs -0 -J% cp -np % dest_dir/
find base_dir/ -iname '*.ftype' -exec cp '{}' dest_dir/ \;

PD: Las citas en -iname '*.ftype' es importante aquí para evitar la expansión por la cáscara.

PPS: El error que se obtiene al utilizar [A-Ma-m]**/*.ftype indica que el patrón no se expandió. No sé zsh muy bien, pero lo más probable es que ** no admite patrones adicionales en el frente.

3voto

staffan Puntos 3299

"Lista de argumentos demasiado larga" se debe a la longitud total de la línea de comandos (el nombre del comando y los argumentos, más un byte para cada uno - más el entorno, en realidad). Se limita a sysctl kern.argmax bytes ( KERN_ARGMAX en el C sysctl interfaz ). La forma habitual de evitar este error es dividir el comando en varias llamadas.

Zsh viene con una función llamada zargs que ayuda a ejecutar automáticamente un comando varias veces con conjuntos sucesivos de argumentos. Es similar al comando externo xargs pero con una sintaxis diferente.

autoload -U zargs
zargs -i -- **/*.ftype -- cp -- {} ../destination

Ponga el autoload línea en su ~/.zshrc para evitar tener que escribirlo cada vez que quiera utilizarlo. (Algunos marcos de configuración de zsh pueden hacerlo por ti).

La opción -i causa zargs para reemplazar {} en el comando por cada argumento sucesivamente. Así se ejecuta cp una vez por argumento. zargs también puede ejecutar el comando con múltiples argumentos a la vez, lo que es más rápido, pero una limitación es que los argumentos agrupados tienen que ir al final de la línea de comandos. Esto no es una buena opción para cp ya que necesita que el destino vaya al final.

GNU cp tiene una opción -T que permite pasar el destino antes que las fuentes, precisamente para facilitar el uso de xargs (y zargs que es similar). Asumiendo que tienes GNU cp instalado como gcp :

zargs -- **/*.ftype -- cp -T ../destination --

Por otra parte, una ventaja de zargs en xargs es que se puede utilizar en una función.

f () { $@[2,-1] $1 }
zargs -- **/*.ftype -- f ../destination cp --

Observe cómo f sólo reordena sus argumentos, no tiene el cp -- … ../destination incorporado. La cuestión es mantener el f llamada al menos tan larga como la cp llamada, de lo contrario zargs construiría una línea de comandos que supera el límite cuando el cp -- y ../destination se añaden partes. Alternativamente, pase un límite más pequeño:

f () { cp -- "$@" ../destination/; }
zargs -s $(($(sysctl kern.argmax) - $#functions[f])) -- **/*.ftype -- f

(o simplemente escriba un límite, por ejemplo zargs -s 999999 -- **/*.ftype -- f ).

Como alternativa, deje de preocuparse por el límite de longitud de la línea de comandos y utilice la función zcp función para hacer copias de lujo. Como antes, pon el autoload y alias líneas en su .zshrc para evitar tener que escribirlas cada vez.

autoload -U zmv
alias zcp='zmv -C'
zcp '**/(*.ftype)' '../destination/$1'

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