grepping dotfiles com -R corretamente?

3

De vez em quando, preciso encontrar um culpado em um arquivo de ponto desconhecido e, em vez de tentar descobrir qual pacote deve ser responsabilizado (por exemplo, xfce4 ou thunar?) e qual é a convenção de nomenclatura deles (.app vs .application vs .some_old_name vs .config / app ...), eu só quero ir para o rápido & caminho sujo:

me@here:~$ grep -IR .* -e culprit

Mas isso é rápido & Maneira suja também é o caminho bobo. Depois de alguns minutos, descubro que .* significa .. , e lá estamos nós. Às vezes eu recorro a provavelmente ainda menos rápido & variante mais suja:

me@here:~$ grep -IR /home/me -e culprit

que acaba por ser um disparate superior, especialmente se eu tiver algum mount ains enorme ou distante no meu $HOME . Pena que eu não consigo descobrir o caminho rápido e limpo e certo. (E minhas cabeças de disco estão lentamente se esgotando.)

É possível conseguir isso dentro da expansão do curinga? Ou seja uma variante de .* que não corresponde a .. (e ../.. ...)?

    
por Alois Mahdal 09.02.2013 / 03:19

8 respostas

3

Graças a este wiki , descobri que há essa variável GLOBIGNORE :

The Bash variable (not shopt) GLOBIGNORE allows you to specify patterns a glob should not match. This lets you work around the infamous "I want to match all of my dot files, but not . or .." problem:

$ echo .*
. .. .bash_history .bash_logout .bashrc .inputrc .vimrc
$ GLOBIGNORE=.:..
$ echo .*
.bash_history .bash_logout .bashrc .inputrc .vimrc

O bom é que isso quase não tem efeitos colaterais (quero dizer, com que frequência você deseja corresponder a .. e . ?), então seria até aceitável para export GLOBIGNORE=.:.. de .bashrc , e para tarefas manuais basta usar o antigo .* glob, como no primeiro exemplo no Q.

me@here:~$ set | grep GLOBIGNORE
GLOBIGNORE=.:.
me@here:~$ grep -IR .* -e culprit
.some-app/config: set culprit=1
me@here:~$
    
por 13.02.2013 / 17:52
6

Se você está no Linux, pode tentar

grep -IR --exclude-dir=".." culprit .*

Desde que você perguntou sobre curingas de shell, meu primeiro pensamento é .[!.]* ..[!.]* , como em

grep -IR culprit .[!.]* ..[!.]*

Qual tem o problema de que grep sairá com um erro se não houver arquivos começando com .. . Para contornar isso, você pode adicionar -s a grep para dizer a ele para ignorar arquivos ausentes:

grep -IRs culprit .[!.]* ..[!.]*

Ou use a opção bash e zsh nullglob para tornar ..[!.]* expandido para nada se não houver arquivos começando com ..

shopt -s nullglob   # for bash
setopt nullglob     # for zsh

grep -IR culprit .[!.]* ..[!.]*

Em todos os itens acima, sempre há find

find . -path "./.*" -exec grep culprit {} +
    
por 09.02.2013 / 05:40
4

Se você tiver o bash disponível, você pode usar extglob para obter somente dotfiles.

shopt -s extglob
grep -IR 'foo' .!(|.)

O operador ! em um glob estendido é "não". Esse padrão corresponde a qualquer coisa que comece com um ponto, excluindo '.' e '..' .

    
por 09.02.2013 / 04:22
1

Eu uso esse script para editar rapidamente os dotfiles:

dirs=($HOME/.$1* $HOME/.$1/ $XDG_CONFIG_HOME/$1/)

IFS=$'\n' 
read -r -d '' -a files /dev/null)
(( ${#files[*]} )) && "$EDITOR" "${files}"

Uma versão mais POSIX:

find "${dirs[@]}" -type f \( -name "*.conf" -o -name "conf" -o -name "config" \
-o -name "*rc" -o -name "*.
    
por 09.02.2013 / 06:09
1
grep -IR culprit .[!.]*

.[!.]* corresponde a todos os arquivos de ponto, exceto os que começam com .. . Como os arquivos de pontos não começam com .. , tudo bem.

Ou você pode usar o zsh, que nunca inclui . ou .. em um glob:

grep -IR culprit .*

Mais esotericamente, no bash, se você tiver a opção extglob ativada ( shopt -s extglob ), isso funciona e inclui ..?* (também funciona em ksh e em zsh após setopt ksh_glob ):

grep -IR culprit !(|.)
    
por 12.02.2013 / 02:39
0

Para resolver seu problema, tente isso em vez disso (no bash), que corresponde a tudo, menos .. :

shopt -s dotglob; grep -e culprit -IR *

Mas na verdade você queria isso,

grep -e culprit -IR .

.* é desnecessário, pois você pode iniciar grep do diretório atual.

    
por 09.02.2013 / 03:52
0

Acabou de encontrar este:

me@here:~$ grep -IR .[a-zA-Z0-9]* -e culprit

feio como o inferno e não é trivial de digitar, mas parece fazer o trabalho. Na maioria das vezes você pode omitir os limites e dígitos:

me@here:~$ grep -IR .[a-z]* -e culprit

Deve haver uma maneira mais agradável, embora ...

    
por 09.02.2013 / 03:33
-3

Tente:

grep -R -e culprit \.*

A barra invertida antes do ponto, eu acho, vai fazer com que seja um ponto literal, em vez de tratar ponto, já que o caractere meta significa correspondência com qualquer átomo.

    
por 12.02.2013 / 05:40