Eu tenho um script bash que limpa a fila de correio periodicamente. Por motivos, optamos por excluir qualquer e-mail para @mms.att.net e outros gateways de e-mail2SMS que estejam há mais de 9 horas na fila e ainda não foram entregues.
Simplificado, o script faz isso:
domains=`cat /etc/mail/email2textdomains.txt`
egrep $domains /var/log/maillog | .... other tasks
e o conteúdo de /etc/mail/email2textdomains.txt
é exatamente
"mms.att.net|vtxt.com|vtext.com|vzwpix.com"
Portanto, a linha egrep deve ser esta, que é exatamente o que eu digitaria na linha de comando.
egrep "mms.att.net|vtxt.com|vtext.com|vzwpix.com" file | ...
Se eu executar assim, será um pipeline de mais de 5 estágios de comandos, cada um lendo stdin do stdout anterior. Esta claramente não é a pesquisa que eu quero fazer.
egrep mms.att.net|vtxt.com|vtext.com|vzwpix.com file | ...
No entanto, quando executados, as duas aspas duplas são tratadas de maneira diferente - elas se tornam parte da string, então estamos essencialmente procurando por
- "mms.att.net
- vtxt.com
- vtext.com
- vzwpix.com"
Claramente, não entendi como as citações funcionam - a resolução foi alterar a linha incluída para remover as aspas duplas, resultando em uma linha que não deveria funcionar, mas funciona.
Eu tentei testar canalizando para od -a
o qual não mostra nenhum caractere não imprimível.
Por que funciona, fazendo com que o conteúdo /etc/mail/email2textdomains.txt
seja exatamente
mms.att.net|vtxt.com|vtext.com|vzwpix.com
quando deve ser um longo pipeline até a falha, conforme escrito?
Uma ótima ferramenta ao tentar depurar esse tipo de coisa é o
set -x
. Usando isso, podemos ver exatamente o que seus comandos estão fazendo:Como você pode ver,
$domains
inclui as aspas. Então, quando você usa comgrep
, você obtém:O que você queria fazer é usar as aspas no nível do shell, antes dos dados serem passados para o
grep
comando, mas como as aspas fazem parte dos dados da variável, elas são tratadas como qualquer outro caractere. A solução mais simples é remover as aspas do arquivo e apenas citar suas variáveis, o que é a melhor prática de qualquer maneira:Como um aparte, using
var=$(command)
é preferível a usingvar=`command`
porque o primeiro é mais claro e permite mais aninhamento eegrep
é obsoleto em favor degrep -E
.Também tome cuidado, pois
.
é um operador regex que corresponde a qualquer caractere único, portanto,grep mms.att.net
na verdade, localiza as linhas que contêmmms
seguido por qualquer caractere único seguido poratt
seguido por qualquer caractere único seguido pornet
. Por exemplo, também corresponderia a uma linha contendo .hammstattinet.com
Portanto, para criar uma
E
expressão regular xtended que corresponda a linhas que contenham qualquer um desses domínios, você não apenas teria que remover os"
s, mas também escapar todos os caracteres em nomes de domínio que também são operadores regex. Para nomes de domínio válidos, isso deve ser limitado a.
.Também esteja ciente de que, para um regex vazio, o comportamento varia entre
grep
as implementações, mas muitos deles reportariam todas as linhas, então você pode querer tratá-lo de maneira especial.Então:
Como alternativa, você pode substituir os
|
s por novas linhas e usar a-F
opçãogrep
(anteriormentefgrep
) para procurarF
strings fixas:@Kaz deve escrever seu comentário para que possa ser a resposta aceita.
Se você deseja evitar,
eval
acho que deve reescrever seu código para colocar aspas adicionais . Minha regra excessivamente simplista é que cada cifrão deve estar entre aspas duplas, a menos que você saiba melhor.Eu mudaria
/etc/mail/email2textdomains.txt
para um domínio por linha, para aproveitar o fato de que grep permite uma nova linha como forma de expressar alternativas, ou sejae diz
As aspas estão apenas na primeira linha para satisfazer minha regra, elas não são necessárias. O
--
está lá para proteger contra uma liderança-
dentro do arquivo textdomains. Usando diretogrep
em vez deegrep
ougrep -E
para aumentar a portabilidade. Com efeito, você está escrevendo