Estou tentando copiar um monte de arquivos abaixo de um diretório e vários arquivos têm espaços e aspas simples em seus nomes. Quando tento encadear find
e grep
com xargs
, recebo o seguinte erro:
find .|grep "FooBar"|xargs -I{} cp "{}" ~/foo/bar
xargs: unterminated quote
Alguma sugestão para um uso mais robusto do xargs?
Isso ocorre no Mac OS X 10.5.3 (Leopard) com BSD xargs
.
--delimiter
opção (-d
). Experimente\n
como delimitador, Isso impede axargs
separação de linhas com espaços em várias palavras / argumentos.Respostas:
Você pode combinar tudo isso em um único
find
comando:Isso manipulará nomes de arquivos e diretórios com espaços neles. Você pode usar
-name
para obter resultados que diferenciam maiúsculas de minúsculas.Nota: O
--
sinalizador transmitido paracp
impede o processamento de arquivos começando com-
como opções.fonte
xargs
não é necessário para solucionar o problema que você está descrevendo,find
já o suporta com a-exec
+
pontuação.find . -print0 | grep --null 'FooBar' | xargs -0 ...
Não sei se
grep
suporta--null
, nem sexargs
suporta-0
, no Leopard, mas no GNU é tudo de bom.fonte
grep -{z|Z}
significa "comporte-se como zgrep" (descompacte) e não o pretendido "imprima um byte zero após cada nome de arquivo". Usegrep --null
para alcançar o último.find . -name 'FooBar' -print0 | xargs -0 ...
?-name
ou-path
funcione bem. O OP especificou o uso degrep
, presumivelmente porque eles querem filtrar a lista usando expressões regulares.xargs -0
em conjuntofind -print0
. O último imprime nomes de arquivos com um terminador NUL e o primeiro recebe arquivos dessa maneira. Por quê? Os nomes de arquivos no Unix podem conter caracteres de nova linha. Mas eles não podem conter caracteres NUL.A maneira mais fácil de fazer o que o pôster original deseja é alterar o delimitador de qualquer espaço em branco para apenas o caractere de fim de linha como este:
fonte
sed -e 's_\(.*\)_"\1"_g'
a citações de força em torno do nome do arquivoxargs
.xargs: illegal option -- d
Isso é mais eficiente, pois não executa o "cp" várias vezes:
fonte
Eu tive o mesmo problema. Aqui está como eu resolvi:
Eu costumava
sed
substituir cada linha de entrada pela mesma linha, mas cercada por aspas duplas. Nased
página de manual, " ... Um e comercial (` `& '') que aparece na substituição é substituído pela string correspondente ao RE ... " - nesse caso.*
, a linha inteira.Isso resolve o
xargs: unterminated quote
erro.fonte
sed s/.*/\"&\"/
para fazê-lo funcionar."
in - a menos que sed também cite aspas?sed
é genial e, por enquanto, a solução correta sem reescrever o problema!Este método funciona no Mac OS X 10.7.5 (Lion):
Também testei a sintaxe exata que você postou. Isso também funcionou bem em 10.7.5.
fonte
-I
implica-L 1
(assim diz o manual), o que significa que o comando cp está sendo executado uma vez por arquivo = v lento.find ... -print0
exargs -0
trabalhar em torno de xargs "por padrão, as cotações são especiais". Segundo, geralmente'{}'
não use{}
comandos passados para xargs, para proteger contra espaços e caracteres especiais.Só não use
xargs
. É um programa interessante, mas não combina bem comfind
casos não triviais.Aqui está uma solução portátil (POSIX), ou seja, que não requer
find
,xargs
oucp
extensões específicas do GNU:Observe o final em
+
vez do mais usual;
.Esta solução:
lida corretamente com arquivos e diretórios com espaços incorporados, novas linhas ou quaisquer caracteres exóticos.
funciona em qualquer sistema Unix e Linux, mesmo aqueles que não fornecem o kit de ferramentas GNU.
não usa o
xargs
que é um programa agradável e útil, mas requer muitos recursos de ajuste e fora do padrão para lidar adequadamente com afind
saída.também é mais eficiente (leia mais rápido ) que o aceito e a maioria, senão todas as outras respostas.
Observe também que, apesar do que é indicado em outras respostas ou comentários, a citação
{}
é inútil (a menos que você esteja usando ofish
shell exótico ).fonte
find
pode fazer o quexargs
faz sem sobrecarga.Procure usar a opção --null commandline para xargs com a opção -print0 em find.
fonte
Para quem confia em comandos, além de encontrar, por exemplo
ls
:fonte
-I
implica-L 1
Acredito que isso funcione de maneira confiável para qualquer personagem, exceto o feed de linha (e eu suspeito que, se você tiver feeds de linha em seus nomes de arquivo, você tem problemas piores do que isso). Não requer o GNU findutils, apenas o Perl, por isso deve funcionar praticamente em qualquer lugar.
fonte
mkdir test && cd test && perl -e 'open $fh, ">", "this-file-contains-a-\n-here"' && ls | od -tx1
|perl -lne 'print quotemeta'
é exatamente o que eu tenho procurado. Outras postagens aqui não me ajudaram porque, em vez defind
precisar usar,grep -rl
reduzi bastante o número de arquivos PHP apenas para os infectados por malware.Eu descobri que a seguinte sintaxe funciona bem para mim.
Neste exemplo, estou procurando os maiores 200 arquivos com mais de 1.000.000 de bytes no sistema de arquivos montado em "/ usr / pcapps".
O liner de linha Perl entre "find" e "xargs" escapa / cita cada espaço em branco para que "xargs" passe qualquer nome de arquivo com espaços em branco incorporados para "ls" como um único argumento.
fonte
Desafio de quadros - você está perguntando como usar o xargs. A resposta é: você não usa xargs, porque não precisa.
O comentário
user80168
descreve uma maneira de fazer isso diretamente com o cp, sem chamar o cp para cada arquivo:Isso funciona porque:
cp -t
sinalizador permite fornecer o diretório de destino próximo ao início decp
, e não perto do final. Deman cp
:O
--
sinalizador indicacp
para interpretar tudo depois como um nome de arquivo, não um sinalizador; portanto, os arquivos que começam com-
ou--
não confundemcp
; você ainda precisa disso porque os caracteres-
/--
são interpretados porcp
, enquanto outros caracteres especiais são interpretados pelo shell.A
find -exec command {} +
variante essencialmente faz o mesmo que xargs. Deman find
:Ao usar isso em localizar diretamente, isso evita a necessidade de um pipe ou uma invocação de shell, para que você não precise se preocupar com caracteres desagradáveis nos nomes de arquivos.
fonte
Esteja ciente de que a maioria das opções discutidas em outras respostas não é padrão em plataformas que não usam os utilitários GNU (Solaris, AIX, HP-UX, por exemplo). Consulte a especificação POSIX para obter o comportamento xargs 'padrão'.
Também acho o comportamento de xargs pelo qual ele executa o comando pelo menos uma vez, mesmo sem entrada, ser um incômodo.
Eu escrevi minha própria versão privada do xargs (xargl) para lidar com os problemas de espaços nos nomes (apenas as novas linhas se separam - embora a combinação 'find ... -print0' e 'xargs -0' seja bastante interessante, pois os nomes dos arquivos não podem contém caracteres ASCII NUL '\ 0'. Meu xargl não é tão completo quanto deveria valer a pena ser publicado - especialmente porque o GNU tem instalações que são pelo menos tão boas.
fonte
find
não precisaxargs
em primeiro lugar (e isso já era verdade há 11 anos).Com o Bash (não POSIX), você pode usar a substituição de processo para obter a linha atual dentro de uma variável. Isso permite que você use aspas para escapar de caracteres especiais:
fonte
Para mim, eu estava tentando fazer algo um pouco diferente. Eu queria copiar meus arquivos .txt na minha pasta tmp. Os nomes de arquivo .txt contêm espaços e caracteres de apóstrofo. Isso funcionou no meu Mac.
fonte
Se as versões find e xarg em seu sistema não suportarem
-print0
e-0
alternar (por exemplo, AIX find e xargs), você poderá usar este código de aparência terrível:Aqui o sed cuidará de escapar dos espaços e das aspas para xargs.
Testado no AIX 5.3
fonte
Criei um pequeno script de invólucro portátil chamado "xargsL" em torno de "xargs", que soluciona a maioria dos problemas.
Ao contrário de xargs, xargsL aceita um nome de caminho por linha. Os nomes de caminho podem conter qualquer caractere, exceto (obviamente) nova linha ou bytes NUL.
Nenhuma citação é permitida ou suportada na lista de arquivos - seus nomes de arquivos podem conter todos os tipos de espaços em branco, barras invertidas, barras de reticulação, caracteres curinga do shell e similares - o xargsL os processará como caracteres literais, sem causar danos.
Como um recurso adicional de bônus, o xargsL não executará o comando uma vez se não houver entrada!
Observe a diferença:
Quaisquer argumentos fornecidos ao xargsL serão passados para o xargs.
Aqui está o script de shell POSIX "xargsL":
Coloque o script em algum diretório no seu $ PATH e não se esqueça de
$ chmod +x xargsL
o script lá para torná-lo executável.
fonte
A versão Perl do bill_starr não funcionará bem para novas linhas incorporadas (apenas lida com espaços). Para aqueles que, por exemplo, Solaris, onde você não possui as ferramentas GNU, uma versão mais completa pode ser (usando sed) ...
ajuste os argumentos find e grep ou outros comandos conforme necessário, mas o sed corrigirá suas novas linhas / espaços / guias.
fonte
Usei a resposta de Bill Star ligeiramente modificada no Solaris:
Isso colocará aspas em cada linha. Eu não usei a opção '-l', embora provavelmente ajude.
A lista de arquivos que eu estava indo embora poderia ter '-', mas não novas linhas. Eu não usei o arquivo de saída com outros comandos, pois quero revisar o que foi encontrado antes de começar a excluí-los massivamente via xargs.
fonte
Eu brinquei um pouco com isso, comecei a contemplar a modificação de xargs e percebi que, para o tipo de caso de uso que estamos falando aqui, uma simples reimplementação no Python é uma idéia melhor.
Por um lado, ter ~ 80 linhas de código para a coisa toda significa que é fácil descobrir o que está acontecendo, e se um comportamento diferente for necessário, você pode simplesmente invadir um novo script em menos tempo do que o necessário para obter uma resposta em algum lugar como Stack Overflow.
Consulte https://github.com/johnallsup/jda-misc-scripts/blob/master/yargs e https://github.com/johnallsup/jda-misc-scripts/blob/master/zargs.py .
Com yargs como está escrito (e o Python 3 instalado), você pode digitar:
para copiar 203 arquivos de cada vez. (Aqui, 203 é apenas um espaço reservado, é claro, e usar um número estranho como 203 deixa claro que esse número não tem outro significado.)
Se você realmente deseja algo mais rápido e sem a necessidade de Python, tome zargs e yargs como protótipos e reescreva em C ++ ou C.
fonte
Você pode precisar grep o diretório Foobar como:
fonte
-i
está obsoleto e-I
deve ser usado.Se você estiver usando o Bash, poderá converter stdout em uma matriz de linhas
mapfile
:Os benefícios são:
Você pode acrescentar outros argumentos aos nomes dos arquivos. Para
cp
, você também pode:no entanto, alguns comandos não possuem esse recurso.
As desvantagens:
Bem ... quem sabe se o Bash está disponível no OS X?
fonte