Não é possível canalizar ou redirecionar a saída do Cygwin grep

3

Como faço para que o grep do Cygwin funcione corretamente em um cmd.exe normal?

> grep -o 'ProductVersion\".*\".*\"' foo.txt | grep -o '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+'
foo.txt:ProductVersion" Value="59.59.140.59"
grep: |: No such file or directory
grep: grep: No such file or directory
grep: [0-9]+\.[0-9]+\.[0-9]+\.[0-9]+: No such file or directory

e

> grep -o 'ProductVersion\".*\".*\"' foo.txt >> blah.txt
foo.txt:ProductVersion" Value="59.59.140.59"
grep: >>: No such file or directory
grep: blah.txt: No such file or directory

Aceitará de bom grado a resposta de outra pessoa, mas modificar meu comando para não usar aspas escapadas resolveu meu problema. Obrigado, @barlop.

Na minha pesquisa específica, consegui alterar

grep -o 'ProductVersion\".*\".*\"' foo.txt >> blah.txt

para

grep -o 'ProductVersion.*Value.*' foo.txt | grep -v Name >> blah.txt

Eu chamaria isso de mais uma solução alternativa.

    
por Thomas 17.11.2011 / 17:16

2 respostas

1

Para o grep do Cygwin

Uma solução alternativa é que você pode especificar o valor ASCII no Bash. " é 22 em hexadecimal.

Dois pontos: você precisa remover as aspas simples ao redor da primeira parte, para que $'\x22' seja interpretado como especial, não como literal.

E para a segunda parte da expressão, você não pode usar apenas -o , tem que ser -oE .

Como + faz parte de ERE e sem -E , é apenas BRE . Acha que + é literal.

Prova + é literal lá .. 55.55.55.55 não corresponde, mas isto irá:

$ echo 3+.3+.3+.3+ | grep -o [0-9]+\.[0-9]+\.[0-9]+\.[0-9]+
3+.3+.3+.3+

Então aqui está a linha que você tinha, mas ajustou ..

Usando o recurso do Bash de expandir os códigos ASCII, em vez de usar aspas. Removendo aspas da primeira parte e adicionando -E à segunda parte:

$ grep -o ProductVersion$'\x22'.*$'\x22'.*$'\x22' foo.txt | grep -oE [0-9]+\.[0
-9]+\.[0-9]+\.[0-9]+
59.59.140.59

ADICIONADO

Se você substituir [0-9]+ por [0-9][0-9]* (que é o mesmo), você poderá usar o grep sem o -E .

Você pode usar grep -P e, em seguida, usar \d para [0-9] , mas é necessário usar aspas na segunda parte. Ou \d .

Na verdade, aqui está uma ótima solução que resolve totalmente o seu problema original. Você só precisa de uma citação em torno do bit problemático. (By the way, eu poderia fazer a expressão regular no segundo semestre mais eficiente usando o operador de repetição, mas isso não é relevante para o problema que tivemos com citações que eu estou focando).

Isso funciona. Eliminando as aspas simples do primeiro bit e usando \" para torná-las cotas literais. Isso contorna o erro das aspas duplas que precisam ser citadas individualmente. (Erro estranho se o findstr do Windows NT tiver algo parecido, mas não com aspas simples, sem dúvida.)

grep -P na segunda parte, nos permite usar \d . Poderíamos colocar aspas em torno da expressão regular no segundo semestre. Ou podemos simplesmente colocar aspas em torno do '\d\ ou, podemos fazer o que eu fiz e usar \d. ( \d sozinho - unescaped e sem aspas, não corresponderá porque é interpretado pelo Bash e reduzido a d quando grep pegar.)

$ grep -o ProductVersion\".*\".*\" foo.txt | grep -oP \d+\.[0-9]+\.[0-9\]+\.[0
-9]+
59.59.140.59

Agora que lidamos com a questão das cotações, tornarei isso mais eficiente com o operador de repetição. A expressão regular de 3{4} significa 3333 . A expressão regular de (fg){4} significaria fgfgfgfg .

$ grep -o ProductVersion\".*\".*\" foo.txt | grep -P '(\d.){4}'
ProductVersion" Value="59.59.140.59""

$ grep -o ProductVersion\".*\".*\" foo.txt | grep -P '('\d.')'{4}
ProductVersion" Value="59.59.140.59""

$ grep -o ProductVersion'"'.*'"'.*'"' foo.txt | grep -P '('\d.')'{4}
ProductVersion" Value="59.59.140.59""
    
por 17.11.2011 / 18:30
4

Você não está usando um shell Unix. As citações são diferentes.

Por algum motivo, você acha que as aspas simples são metacaracteres no interpretador de comandos da Microsoft. Eles não são. Eles não têm significado especial. Além disso, as barras invertidas não têm significado especial para o interpretador de comandos da Microsoft. Eles não são o caractere de escape para citar metacaracteres. Esse é o caret. São aspas duplas que importam: elas citam metacaracteres, como < , > e | , para impedir que o interpretador de comandos as reconheça, e quaisquer barras invertidas que as precedam são irrelevantes.

Assim, sua linha de comando é dividida assim, com as strings citadas enfatizadas:

grep -o 'ProductVersion\".*\".*\"' foo.txt | grep -o '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+'

Como você pode ver, o que você achava que era um pipeline é, na verdade, uma sequência citada terminada incorretamente a partir de sua terceira aspa dupla e se estendendo até o final da linha. Você está realmente executando apenas o um grep comando, e você está dando a ele todo o texto entre aspas no final de sua cauda de comando. Seu comando grep sabe sobre aspas simples e está quebrando a cauda do comando que recebe do interpretador de comandos, que ainda contém as aspas duplas (porque o interpretador de comandos reconhece, mas não as remove) em sete palavras :

  1. -o
  2. ProductVersion\".*\".*\"
  3. foo.txt
  4. |
  5. grep
  6. -o
  7. [0-9]+\.[0-9]+\.[0-9]+\.[0-9]+

Daí as mensagens de erro sobre esses arquivos. Mas isso é o seu comando grep do . O interpretador de comandos não opera em termos de palavras, e os programas Win32 recebem um único comando tail , não um vetor de argumento como no paradigma Unix. Cabe ao programa chamado dividir a cauda do comando em palavras, se quiser operar na moda Unix (e linguagem C). (As bibliotecas de suporte de tempo de execução da maioria das implementações de linguagem C e C ++ para o Win32 fazem isso dividindo os bastidores. No entanto, ainda é o programa chamado, não o interpretador de comandos.)

De fato, muitos programas Win32 C e C ++ que não usam as bibliotecas Cygwin não tratam as aspas simples, especialmente, mais do que o próprio interpretador de comandos faz. Eles acabarão dividindo a cauda do comando em apenas duas palavras:

  1. -o
  2. 'ProductVersion\.*".*"' foo.txt | grep -o [0-9]+\.[0-9]+\.[0-9]+\.[0-9]+

O que precede é que programa compilado com a C / da Microsoft O compilador C ++ faria , por exemplo. Ironicamente, esses programas C / C ++ reconhecerão barras invertidas dentro de strings entre aspas, mesmo que o interpretador de comandos não o faça. Então, eles acham que sua cauda de comando é assim, com uma grande string terminada indevidamente terminada, em vez de duas strings entre aspas:

 -o 'ProductVersion\".*\".*\"' foo.txt | grep -o '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+'

Sim, este é um script de comando que escreve pesadelo. Essencialmente, você tem que saber quais convenções o programa que você está executando adere a fim de decidir como citar o vetor de argumento que você deseja passar para ele. O Cygwin tem uma convenção. Programas C e C ++ compilados com compiladores comerciais C e C ++ para Win32 têm outros. (Nos anos 80 e 90, a Borland, a Watcom e a Microsoft discordaram sobre o comando tail lexing em seus compiladores C / C ++ para DOS, e houve uma diferença muito sutil na manipulação de caracteres de barra invertida entre os programas como conseqüência.) Outras linguagens de programação fazem coisas de outras maneiras sutilmente diferentes.

Você sabe que o comando grep é um programa do Cygwin, portanto é necessário construir uma linha de comando que (a) o interpretador de comandos reconheça corretamente como dois comandos simples unidos em um pipeline de comando e que (b) O comando grep será corretamente dividido em palavras usando o algoritmo Cygwin. Aqui está uma maneira:

grep -o 'ProductVersion^".*\^".*\^"' foo.txt | grep -o '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+'
    
por 18.11.2011 / 03:52