Estoy tratando de copiar un montón de archivos debajo de un directorio y varios archivos tienen espacios y comillas simples en sus nombres. Cuando trato de encadenar find
y grep
con xargs
, me sale el siguiente error:
find .|grep "FooBar"|xargs -I{} cp "{}" ~/foo/bar
xargs: unterminated quote
¿Alguna sugerencia para un uso más robusto de xargs?
Esto está en Mac OS X 10.5.3 (Leopard) con BSD xargs
.
--delimiter
opción (-d
). Pruébelo\n
como delimitador, esto evita laxargs
separación de líneas con espacios en varias palabras / argumentos.Respuestas:
Puedes combinar todo eso en un solo
find
comando:Esto manejará nombres de archivos y directorios con espacios en ellos. Puede usar
-name
para obtener resultados sensibles a mayúsculas y minúsculas.Nota: La
--
bandera pasada acp
evita que procese archivos que comienzan-
como opciones.fuente
xargs
no es necesario para abordar el problema que está describiendo,find
ya lo admite con la-exec
+
puntuación.find . -print0 | grep --null 'FooBar' | xargs -0 ...
No sé si los
grep
apoyos--null
, ni si losxargs
apoyos-0
, en Leopard, pero en GNU, todo está bien.fuente
grep -{z|Z}
significa "comportarse como zgrep" (descomprimir) y no el "imprimir un byte cero después de cada nombre de archivo". Úselogrep --null
para lograr esto último.find . -name 'FooBar' -print0 | xargs -0 ...
?-name
o-path
funciona bien. El OP ha especificado el uso degrep
, presumiblemente porque quieren filtrar la lista usando expresiones regulares.xargs -0
junto confind -print0
. El último imprime los nombres de archivo con un terminador NUL y el primero recibe los archivos de esa manera. ¿Por qué? Los nombres de archivo en Unix pueden contener caracteres de nueva línea. Pero no pueden contener caracteres NUL.La forma más fácil de hacer lo que quiere el póster original es cambiar el delimitador de cualquier espacio en blanco al carácter de final de línea como este:
fuente
sed -e 's_\(.*\)_"\1"_g'
a las cotizaciones de la fuerza de todo el nombre del archivoxargs
.xargs: illegal option -- d
Esto es más eficiente ya que no ejecuta "cp" varias veces:
fuente
Tuve el mismo problema. Así es como lo resolví:
Solía
sed
sustituir cada línea de entrada con la misma línea, pero rodeado de comillas dobles. Desde lased
página del manual, " ... Un ampersand (` `& '') que aparece en el reemplazo se reemplaza por la cadena que coincide con el RE ... " - en este caso.*
, la línea completa.Esto resuelve el
xargs: unterminated quote
error.fuente
sed s/.*/\"&\"/
para que funcione."
in, a menos que sed también cite comillas.sed
es genial y por ahora la solución correcta sin tener que volver a escribir el problema!Este método funciona en Mac OS X v10.7.5 (Lion):
También probé la sintaxis exacta que publicaste. Eso también funcionó bien en 10.7.5.
fuente
-I
implica-L 1
(así lo dice el manual), lo que significa que el comando cp se ejecuta una vez por archivo = v lento.find ... -print0
yxargs -0
para trabajar alrededor de xargs "por defecto las comillas son especiales". En segundo lugar, generalmente use'{}'
no{}
en comandos pasados a xargs, para proteger contra espacios y caracteres especiales.Simplemente no lo uses
xargs
. Es un programa ordenado, pero no funciona bienfind
cuando se trata de casos no triviales.Aquí hay una solución portátil (POSIX), es decir, una que no requiere
find
,xargs
ocp
extensiones específicas de GNU:Tenga en cuenta el final en
+
lugar de lo más habitual;
.Esta solución:
maneja correctamente archivos y directorios con espacios incrustados, nuevas líneas o cualquier personaje exótico.
funciona en cualquier sistema Unix y Linux, incluso aquellos que no proporcionan el kit de herramientas GNU.
no utiliza
xargs
cuál es un programa agradable y útil, pero requiere demasiados ajustes y características no estándar para manejar correctamente lafind
salida.También es más eficiente (leer más rápido ) que las respuestas aceptadas y la mayoría, si no todas, las demás.
Tenga en cuenta también que, a pesar de lo que se indica en algunas otras respuestas o comentarios, la cita
{}
es inútil (a menos que esté utilizando elfish
shell exótico ).fuente
find
puede hacer lo quexargs
hace sin gastos generales.Considere el uso de la opción de línea de comando --null para xargs con la opción -print0 en find.
fuente
Para aquellos que dependen de comandos, además de encontrar, por ejemplo
ls
:fuente
-I
implica-L 1
Creo que esto funcionará de manera confiable para cualquier carácter, excepto el avance de línea (y sospecho que si tiene avances de línea en sus nombres de archivo, entonces tiene problemas peores que este). No requiere GNU findutils, solo Perl, por lo que debería funcionar prácticamente en cualquier lugar.
fuente
mkdir test && cd test && perl -e 'open $fh, ">", "this-file-contains-a-\n-here"' && ls | od -tx1
|perl -lne 'print quotemeta'
es exactamente lo que he estado buscando. Otras publicaciones aquí no me ayudaron porque en lugar de lofind
que necesitaba usargrep -rl
para reducir enormemente la cantidad de archivos PHP a solo los infectados por malware.He descubierto que la siguiente sintaxis funciona bien para mí.
En este ejemplo, estoy buscando los 200 archivos más grandes de más de 1,000,000 de bytes en el sistema de archivos montado en "/ usr / pcapps".
El delineador de línea Perl entre "find" y "xargs" escapa / cita cada espacio en blanco para que "xargs" pase cualquier nombre de archivo con espacios en blanco incrustados a "ls" como argumento único.
fuente
Reto de marco: estás preguntando cómo usar xargs La respuesta es: no usas xargs, porque no lo necesitas.
El comentario de
user80168
describe una forma de hacer esto directamente con cp, sin llamar a cp para cada archivo:Esto funciona porque:
cp -t
bandera permite dar el directorio de destino cerca del principiocp
, en lugar de cerca del final. Deman cp
:La
--
bandera le dicecp
que interprete todo después como un nombre de archivo, no como una bandera, por lo que los archivos que comienzan con-
o--
no confundencp
; aún necesita esto porque los caracteres-
/--
son interpretados porcp
, mientras que cualquier otro carácter especial es interpretado por el shell.La
find -exec command {} +
variante esencialmente hace lo mismo que xargs. Deman find
:Al usar esto en find directamente, esto evita la necesidad de una tubería o una invocación de shell, por lo que no necesita preocuparse por los caracteres desagradables en los nombres de archivo.
fuente
Tenga en cuenta que la mayoría de las opciones discutidas en otras respuestas no son estándar en plataformas que no utilizan las utilidades GNU (Solaris, AIX, HP-UX, por ejemplo). Ver el POSIX especificación para el comportamiento xargs 'estándar'.
También encuentro que el comportamiento de xargs por el cual ejecuta el comando al menos una vez, incluso sin entrada, es una molestia.
Escribí mi propia versión privada de xargs (xargl) para tratar los problemas de espacios en los nombres (solo las nuevas líneas se separan, aunque la combinación 'find ... -print0' y 'xargs -0' es bastante clara dado que los nombres de archivos no pueden contienen caracteres ASCII NUL '\ 0'. Mi xargl no está tan completo como debería valer la pena publicar, especialmente porque GNU tiene instalaciones que son al menos tan buenas.
fuente
find
no necesitaxargs
en primer lugar (y eso ya era cierto hace 11 años).Con Bash (no POSIX) puede usar la sustitución de procesos para obtener la línea actual dentro de una variable. Esto le permite usar comillas para escapar de caracteres especiales:
fuente
Para mí, estaba tratando de hacer algo un poco diferente. Quería copiar mis archivos .txt en mi carpeta tmp. Los nombres de archivo .txt contienen espacios y caracteres de apóstrofe. Esto funcionó en mi Mac.
fuente
Si las versiones find y xarg en su sistema no son compatibles
-print0
y-0
cambian (por ejemplo, AIX find y xargs), puede usar este código de aspecto terrible:Aquí sed se encargará de escapar de los espacios y las comillas para xargs.
Probado en AIX 5.3
fuente
Creé un pequeño script de contenedor portátil llamado "xargsL" alrededor de "xargs" que aborda la mayoría de los problemas.
Al contrario de xargs, xargsL acepta un nombre de ruta por línea. Los nombres de ruta pueden contener cualquier carácter excepto (obviamente) nueva línea o bytes NUL.
No se permite ni admite el uso de comillas en la lista de archivos: sus nombres de archivo pueden contener todo tipo de espacios en blanco, barras diagonales inversas, comillas invertidas, caracteres comodín de shell y similares: xargsL los procesará como caracteres literales, sin causar daño.
Como una característica adicional, ¡xargsL no ejecutará el comando una vez si no hay entrada!
Tenga en cuenta la diferencia:
Cualquier argumento dado a xargsL se pasará a xargs.
Aquí está el script de shell POSIX "xargsL":
Ponga el script en algún directorio en su $ PATH y no olvide
$ chmod +x xargsL
el script allí para hacerlo ejecutable.
fuente
La versión Perl de bill_starr no funcionará bien para líneas nuevas incrustadas (solo hace frente a espacios). Para aquellos en, por ejemplo, Solaris donde no tiene las herramientas GNU, una versión más completa podría ser (usando sed) ...
ajuste los argumentos find y grep u otros comandos según lo requiera, pero sed arreglará sus nuevas líneas / espacios / pestañas incrustadas.
fuente
Solía respuesta de Bill estrella ligeramente modificada en Solaris:
Esto pondrá comillas alrededor de cada línea. No utilicé la opción '-l' aunque probablemente ayudaría.
Sin embargo, la lista de archivos a la que iba podría tener '-', pero no nuevas líneas. No he usado el archivo de salida con ningún otro comando, ya que quiero revisar lo que se encontró antes de comenzar a eliminarlos masivamente a través de xargs.
fuente
Jugué un poco con esto, comencé a contemplar la modificación de xargs y me di cuenta de que para el tipo de caso de uso del que estamos hablando aquí, una simple reimplementación en Python es una mejor idea.
Por un lado, tener ~ 80 líneas de código para todo significa que es fácil darse cuenta de lo que está sucediendo, y si se requiere un comportamiento diferente, puede piratearlo en un nuevo script en menos tiempo del necesario para obtenerlo. una respuesta en algún lugar como Stack Overflow.
Ver https://github.com/johnallsup/jda-misc-scripts/blob/master/yargs y https://github.com/johnallsup/jda-misc-scripts/blob/master/zargs.py .
Con los hilos como están escritos (y Python 3 instalado) puede escribir:
hacer la copia de 203 archivos a la vez. (Aquí 203 es solo un marcador de posición, por supuesto, y el uso de un número extraño como 203 deja en claro que este número no tiene otra importancia).
Si realmente quieres algo más rápido y sin la necesidad de Python, toma zargs e hilos como prototipos y reescribe en C ++ o C.
fuente
Puede que necesite grep directorio de Foobar como:
fuente
-i
está en desuso y-I
debe usarse en su lugar.Si está utilizando Bash, puede convertir stdout en una matriz de líneas de la siguiente manera
mapfile
:Los beneficios son:
Puede agregar otros argumentos a los nombres de archivo. Para
cp
, usted también puede:sin embargo, algunos comandos no tienen esa característica.
Las desventajas:
Bueno ... ¿quién sabe si Bash está disponible en OS X?
fuente