Digamos que eu queira copiar o conteúdo de um diretório, excluindo arquivos e pastas cujos nomes contenham a palavra 'Música'.
cp [exclude-matches] *Music* /target_directory
O que deve acontecer no lugar de [excluir exclusões] para fazer isso?
bash
shell
pattern-matching
glob
user4812
fonte
fonte
ls /dir/*/!(base*)
f
, excetofoo
?A
extglob
opção shell oferece uma combinação de padrões mais poderosa na linha de comando.Você liga
shopt -s extglob
e desliga comshopt -u extglob
.No seu exemplo, você faria inicialmente:
O completo disponível ext terminou glob operadores bing são (excerto
man bash
):Portanto, por exemplo, se você quiser listar todos os arquivos no diretório atual que não são
.c
ou.h
arquivos, faça:Obviamente, o globing normal de shell funciona, então o último exemplo também pode ser escrito como:
fonte
.c
ou.h
ser um diretório.D
, mas não o conteúdo dos subdiretórios que podem estar contidos no diretórioD
.Não no bash (que eu saiba), mas:
Eu sei que isso não é exatamente o que você estava procurando, mas resolverá o seu exemplo.
fonte
Se você quiser evitar o custo de mem do uso do comando exec, acredito que você pode fazer melhor com o xargs. Eu acho que o seguinte é uma alternativa mais eficiente para
fonte
Em festa, uma alternativa para
shopt -s extglob
é aGLOBIGNORE
variável . Não é realmente melhor, mas acho mais fácil lembrar.Um exemplo que pode ser o que o pôster original queria:
Quando terminar,
unset GLOBIGNORE
será possívelrm *techno*
no diretório de origem.fonte
Você também pode usar um
for
loop bastante simples :fonte
-maxdepth 1
para não recursivo?find
de backticks quebrará de maneira desagradável se encontrar algum nome de arquivo não trivial.Minha preferência pessoal é usar o grep e o comando while. Isso permite escrever scripts poderosos e legíveis, garantindo que você acabe fazendo exatamente o que deseja. Além disso, usando um comando de eco, você pode executar uma execução a seco antes de executar a operação real. Por exemplo:
imprimirá os arquivos que você acabará copiando. Se a lista estiver correta, a próxima etapa é simplesmente substituir o comando echo pelo comando copy da seguinte maneira:
fonte
bash
você pode usarwhile IFS='' read -r filename
, mas as novas linhas ainda são um problema. Em geral, é melhor não usarls
para enumerar arquivos; ferramentas comofind
são muito mais adequadas.for file in *; do case ${file} in (*Music*) ;; (*) cp "${file}" /target_directory ; echo ;; esac; done
Um truque que eu não vi aqui ainda que não usa
extglob
,find
ougrep
é tratar duas listas de arquivos como conjuntos e "diff" -los usandocomm
:comm
é preferível aodiff
contrário, porque não possui crosta extra.Isso retorna todos os elementos do conjunto 1
ls
, que também não estão no conjunto 2ls *Music*
,. Isso requer que os dois conjuntos estejam na ordem classificada para funcionar corretamente. Não há problema parals
a expansão glob, mas se você estiver usando algo comofind
, não se esqueça de invocarsort
.Potencialmente útil.
fonte
comm -23 <(ls) exclude_these.list
Uma solução para isso pode ser encontrada com o find.
O Find tem algumas opções, você pode ser bem específico sobre o que incluir e excluir.
Edit: Adam nos comentários observou que isso é recursivo. As opções de localização mindepth e maxdepth podem ser úteis para controlar isso.
fonte
find -maxdepth 1 -not -name '*Music*'
/ target_directoryO trabalho a seguir lista todos os
*.txt
arquivos no diretório atual, exceto aqueles que começam com um número.Isso funciona em
bash
,dash
,zsh
e todos os outros shells compatíveis com POSIX.Na linha um, o padrão
/some/dir/*.txt
fará com que ofor
loop itere sobre todos os arquivos em/some/dir
cujo nome termina.txt
.Na linha dois, uma declaração de caso é usada para eliminar arquivos indesejados. - A
${FILE##*/}
expressão retira qualquer componente principal do nome do diretório do nome do arquivo (aqui/some/dir/
) para que os padrões possam corresponder apenas ao nome da base do arquivo. (Se você estiver eliminando apenas os nomes de arquivos com base em sufixos, poderá abreviá-los$FILE
.)Na linha três, todos os arquivos correspondentes ao
case
padrão[0-9]*
) serão ignorados (acontinue
instrução pula para a próxima iteração dofor
loop). - Se você quiser, pode fazer algo mais interessante aqui, por exemplo, como pular todos os arquivos que não começam com uma letra (a – z) usando[!a-z]*
, ou você pode usar vários padrões para pular vários tipos de nomes de arquivos, por exemplo,[0-9]*|*.bak
pular arquivos de ambos os.bak
arquivos e arquivos que não começam com um número.fonte
*.txt
vez de apenas*
). Corrigido agora.isso faria excluindo exatamente 'Música'
isso e aquilo para excluir coisas como Music? * ou *? Music
fonte
cp
página de manual no MacOS tem uma-a
opção, mas faz algo totalmente diferente. Qual plataforma suporta isso?