Como ignorar diretórios vazios ao usar 'rm' com curingas para vários diretórios em zsh?

3

Quando tento excluir todos os arquivos de dois ou mais subdiretórios em zsh e um diretório já está vazio, os diretórios a seguir são ignorados e os arquivos permanecem.

Exemplo:

$ mkdir dir1
$ mkdir dir2
$ touch dir2/blah

# avoid the zsh safety prompt; this may not be necessary for this
# example, just for ease of use here
$ setopt rm_star_silent
$ rm -r dir1/* dir2/*
zsh: no matches found: dir1/*
$ ls dir2
blah

No bash, o diretório já vazio não pára rm de prosseguir para dir2 e dir2/blah é removido.

O que é esse recurso zsh e existe uma maneira de deixar o rm se comportar como bash ?

    
por Stéphane Chazelas 11.01.2017 / 03:12

3 respostas

2

Ao contrário de bash , zsh por padrão relata um erro caso um padrão de geração de nome de arquivo não tenha correspondência. Esse comportamento pode ser alterado globalmente ou em uma base por padrão.

Para evitar que mensagens de erro não correspondam padrão globalmente, você pode definir uma das opções NULL_GLOB ou CSH_NULL_GLOB :

  • setopt nullglob
    

    Se um padrão não tiver correspondência, ele será removido da lista de argumentos. Nenhuma mensagem de erro será impressa. No seu exemplo

    rm dir1/* dir2/*
    

    seria apenas expandido para

    rm dir2/blah
    
  • setopt cshnullglob
    

    Também remove padrões não correspondentes e não imprime uma mensagem de erro, a menos que nenhum dos padrões tenha correspondência.

Para evitar mensagens de erro para padrões únicos, você pode usar o qualificador de glob N , que se comporta como se a opção NULL_GLOB estivesse ativada para esse padrão:

rm dir1/*(N) dir2/*(N)

Isso também seria expandido para

rm dir2/blah
    
por 11.01.2017 / 10:57
2

A melhor maneira é torná-lo um glob único que corresponda aos arquivos em ambos os diretórios.

rm (dir1|dir2)/*

Dessa forma, o comando ainda não será executado se nenhum arquivo for encontrado.

No entanto, observe que dir1 / dir2 não pode conter / .

Nesses casos, você pode fazer isso:

files=(foo/bar/*(N) bar/baz/*(N))
if ((#files)); then
  rm $files
else
  echo >&2 No matching file
fi

Ou use cshnullglob para obter o comportamento csh ou pre-Bourne sh. Isso ainda é melhor do que reverter para o comportamento falso (IMO) de bash (onde globs não correspondentes são passados como no comando), o que você pode fazer com:

set +o nomatch
    
por 11.01.2017 / 11:40
-2

Uma boa explicação pode ser encontrada aqui:

link

A essência é:

By default, ZSH will generate the filenames and throw an error before executing the command if it founds no matches.

Seu diretório vazio não gerará correspondências e, portanto, um erro. Como a resposta indica, você pode:

  1. Coloque o argumento entre aspas (por exemplo, rm -r "dir1/*" "dir2/*" ) OR
  2. Definindo unsetopt nomatch no seu arquivo .zshrc OU
  3. Pré-posicionamento você pode comandar com a variável de ambiente noglob (por exemplo, noglob rm -r dir1/* dir2/* )
por 11.01.2017 / 03:26

Tags