Estou usando grep
para pesquisar padrões correspondentes dentro de arquivos e copiar seu nome de arquivo da saída. Como faço muito essa operação, posso acabar copiando :
também. Portanto, é possível adicionar dois espaços antes da primeira semi-coluna correspondente ou final do nome do arquivo?
$ grep -Hrn -e "zorro" --color=always --exclude-dir=dir -I -F . | \
cut -c 11- | awk '$0="\033[33;35m"$0' | tr -s '[:space:]'
doo.tex:1:zorro alper alper alper skfjsdlkfj dslfj dslkj
saída desejada:
doo.tex :1:zorro alper alper alper skfjsdlkfj dslfj dslkj
^
<two space added>
Meu primeiro porém foi para awk
Mas isso está dando mais trabalho do que o necessário, eu acho, dividindo e juntando a linha novamente.
A alternativa sed é bastante concisa
substituindo os primeiros dois pontos por 2 espaços e dois pontos.
Em relação aos nomes de arquivos com conversa de dois pontos:
Lendo a página de manual do GNU grep: use a
-Z
opção: "Produza um byte zero (o caractere ASCII NUL) em vez do caractere que normalmente segue um nome de arquivo."Então:
Se tudo o que você precisa é de uma lista de nomes de arquivos contendo texto que corresponda a um padrão, como "zorro", e você pretende usar esses nomes de arquivos com outro programa, então você pode fazer algo como o seguinte para criar um array bash contendo os nomes dos arquivos, e evite muito copiar e colar manualmente com o mouse.:
mapfile
é um comando interno do bash que preenche uma matriz de stdin. Nesse caso, stdin está sendogrep
executado como uma substituição de processo . Estou usando-d ''
withmapfile
para dizer que a entrada será delimitada por caracteres NUL e-Z
comgrep
para que ele produza uma lista separada por NUL de nomes de arquivos correspondentes. Isso funcionará com qualquer nome de arquivo, não importa quais caracteres estejam no nome - incluindo dois pontos, espaços, novas linhas e metacaracteres de shell.Você pode ver o que está no array com
declare -p myfiles
, ou usar os elementos do array como argumentos para outro programa (por exemploprintf '%s\'n' "${myfiles[@]}"
), ou em um loop comofor f in "${myfiles[@]}"; do echo "$f" ; done
.Nota: a
-l
opção do grep será encerrada após a primeira correspondência (igual à-m
opção), o que acelerará a pesquisa em arquivos onde a string de pesquisa aparece no início do arquivo. Em arquivos onde o padrão não aparece, ele ainda precisa ler o arquivo inteiro.BTW, se a razão pela qual você está usando a
-I
opção é que você deseja evitar arquivos binários (como saída .pdf ou .dvi do TeX), então você pode usarfind
em vez degrep -r
. Por exemplo:Se você precisar de critérios de seleção mais complicados, além do que o grep é capaz, você pode usar awk ou perl ou qualquer outra coisa em vez de grep. por exemplo, se você quisesse apenas nomes de arquivos em que "zorro" aparecesse na linha 3 do arquivo:
Este é apenas um exemplo simples - se você puder pensar em um critério e escrevê-lo como um script perl (ou awk ou python ou qualquer outro), poderá usá-lo para preencher seletivamente a matriz. Você pode usar qualquer comando, ou qualquer pipeline de comandos longo e complicado, desde que imprima os nomes dos arquivos em stdout separados por um caractere NUL.
Nota:
close(ARGV)
fecha o arquivo atual e pula para o próximo, se houver, independentemente de o nome do arquivo ter sido impresso ou não. Isso significa que ele nunca precisa ler mais de três linhas de qualquer arquivo, então será muito mais rápido se você tiver muitos arquivos grandes para pesquisar.Nota 2: o
\Q
and\E
é a maneira do perl de fazer uma pesquisa de string fixa, semelhante ao-F
grep. Se você estivesse usando o awk, você poderia fazer algo semelhante com aindex()
função.