Acabo de hacer una pregunta relacionada con cómo puedo contar los archivos de extensión particular. Ahora quiero cp
estos archivos a un nuevo dir
.
Estoy intentando,
cp *.prj ../prjshp/
y
cp * | grep '\.prj$' ../prjshp/
pero están dando el mismo error,
bash: / bin / cp: lista de argumentos demasiado larga
¿Cómo los copio?
command-line
files
Sam007
fuente
fuente
Respuestas:
cp *.prj ../prjshp/
es el comando correcto, pero ha encontrado un caso raro en el que se encuentra con una limitación de tamaño. El segundo comando que probaste no tiene ningún sentido.Un método es ejecutar
cp
los archivos en fragmentos. Elfind
comando sabe cómo hacer esto:find
atraviesa el directorio actual y los directorios debajo de él de forma recursiva.-maxdepth 1
significa detenerse a una profundidad de 1, es decir, no recurrir a subdirectorios.-name '*.prj'
significa actuar solo en los archivos cuyo nombre coincide con el patrón especificado. Tenga en cuenta las comillas alrededor del patrón: será interpretado por elfind
comando, no por el shell.-exec … {} +
significa ejecutar el comando especificado para todos los archivos. Invoca el comando varias veces si es necesario, teniendo cuidado de no exceder el límite de la línea de comando.mv -t ../prjshp
mueve los archivos especificados a../prjshp
. La-t
opción se usa aquí debido a una limitación delfind
comando: los archivos encontrados (simbolizados por{}
) se pasan como el último argumento del comando, no puede agregar el destino después.Otro método es usar
rsync
.rsync -r … . ../prjshp
copia el directorio actual en forma../prjshp
recursiva.--include='*.prj' --exclude='*'
significa copiar archivos que coinciden*.prj
y excluir todo lo demás (incluidos los subdirectorios, por.prj
lo que no se encontrarán archivos en subdirectorios).fuente
cp * | grep '\.prj$' ../prjshp/
no tiene ningún sentido, pero puede ser sintácticamente válido, si se*
expande a la lista de archivos, siendo el último un directorio (también conocido comocp SOURCE1 SOURCE2....DEST
). La tubería no tiene ningún sentido, claro, pero también sigue siendo sintácticamente válida en lo que respecta al shell:dup()
los descriptores de archivos estarán bien, es solo que el extremo del lector de la tubería no obtendrá ningún dato porquecp
no escribe ninguno .Este comando copia los archivos uno por uno y funcionará incluso si hay demasiados para
*
expandirlos en un solocp
comando:fuente
Hay 3 puntos clave a tener en cuenta al enfrentar un
Argument list too long
error:La longitud de los argumentos de la línea de comandos está limitada por la
ARG_MAX
variable, que según la definición POSIX es "... [m] longitud máxima de argumento para las funciones ejecutivas, incluidos los datos del entorno" (énfasis agregado) ". Es decir, cuando el shell ejecuta un no -compilado, tiene que llamar a uno de ellosexec()
para generar el proceso de ese comando, y ahí es dondeARG_MAX
entra en juego. Además, el nombre o la ruta al comando en sí (por ejemplo/bin/echo
) juega un papel importante.Los comandos integrados de Shell se ejecutan mediante shell, lo que significa que el shell no utiliza la
exec()
familia de funciones y, por lo tanto, no se ve afectado por laARG_MAX
variable.Ciertos comandos, como
xargs
yfind
son conscientes de laARG_MAX
variable y realizan acciones repetidamente por debajo de ese límiteDe los puntos anteriores y como se muestra en la excelente respuesta de Kusalananda a la pregunta relacionada, esto
Argument list too long
también puede ocurrir cuando el entorno es grande. Por lo tanto, teniendo en cuenta que el entorno de cada usuario puede variar, y el tamaño del argumento en bytes es relevante, es difícil encontrar un solo número de archivos / argumentos.¿Cómo manejar tal error?
La clave es centrarse no en la cantidad de archivos, sino en si el comando que va a utilizar implica una
exec()
familia de funciones y tangencialmente: el espacio de la pila.Use incorporados en shell
Como se discutió anteriormente, las funciones integradas de shell son inmunes al
ARG_MAX
límite, es decir, cosas comofor
loop,while
loop, built-inecho
y built-inprintf
: todas ellas funcionarán lo suficientemente bien.En la pregunta relacionada sobre la eliminación de archivos, había una solución como tal:
Tenga en cuenta que esto usa el shell incorporado
printf
. Si llamamos a lo externoprintf
, eso implicaráexec()
, por lo tanto, fallará con una gran cantidad de argumentos:matrices de bash
Según una respuesta de jlliagre,
bash
no impone límites a las matrices, por lo que también se puede construir una matriz de nombres de archivo y usar segmentos por iteración de bucle, como se muestra en la respuesta de danjpreron :Esto, sin embargo, tiene la limitación de ser específico de bash y no POSIX.
Aumenta el espacio de la pila
A veces puede ver que la gente sugiere aumentar el espacio de la pila con
ulimit -s <NUM>
; en Linux, el valor ARG_MAX es 1/4 del espacio de pila para cada programa, lo que significa que aumentar el espacio de pila aumenta proporcionalmente el espacio para argumentos.De acuerdo con la respuesta de Franck Dernoncourt , que cita Linux Journal, también se puede recompilar el kernel de Linux con mayor valor para páginas de memoria máxima para argumentos, sin embargo, eso es más trabajo del necesario y abre el potencial para explotaciones como se indica en el artículo citado de Linux Journal.
Evitar la cáscara
Otra forma, es usar
python
opython3
que viene por defecto con Ubuntu. El ejemplo de python + here-doc a continuación, es algo que personalmente utilicé para copiar un gran directorio de archivos en algún lugar en el rango de 40,000 elementos:Para recorridos recursivos, puede usar os.walk .
Ver también:
fuente
En mi humilde opinión, las herramientas óptimas para tratar con hordas de archivos son
find
yxargs
. Verman find
. Verman xargs
.find
, con su modificador-print0
, produce unaNUL
lista separada de nombres de archivo (los nombres de archivo pueden contener cualquier execpt de caracteresNUL
o/
) quexargs
comprenda, utilizando el modificador-0
.xargs
luego construye el comando más largo permitido (la mayoría de los nombres de archivo, sin medio nombre de archivo al final) y lo ejecuta.xargs
repite esto hastafind
que no proporcione más nombres de archivo. Correxargs --show-limits </dev/null
para ver los límites.Para resolver su problema, (y después de verificar
man cp
para encontrar--target-directory=
):fuente