grep "^$1" mais ou menos funciona, mas como faço para escapar "$1" então o grep não interpreta nenhum caractere especialmente?

Ou existe uma maneira melhor?

Editar: Eu não quero pesquisar por "^$1", mas por uma string fixa inserida dinamicamente que deve apenas ser correspondido se estiver no início de uma linha. Isso é o que eu quis dizer com $1.

Comentários

  • Você tentou usar aspas simples em vez de aspas duplas, por exemplo grep '^$1'? Ou ‘ não quis dizer que deseja evitar que $1 seja expandido pelo shell?
  • @mnille Eu não ‘ não quero pesquisar por ‘ ^ $ 1 ‘, mas por um inserido dinamicamente string fixa que só deve ser correspondida se ‘ está no início de uma linha. Isso ‘ é o que eu quis dizer com $ 1.
  • Você pode fazer isso com grep também, mas você ‘ primeiro terá que escapar qualquer caractere especial em sua string, por exemplo printf %s ^;printf %s "$1" | sed 's/[][\.*^$]/\\&/g'; } | grep -f- infile
  • @don_crissti que ‘ é melhor do que algumas das outras respostas. Importa-se de torná-lo um?
  • @roaima – Eu sei, mas há ‘ já um monte de respostas aqui e isso (escapar dos caracteres especiais dentro de vars) é algo que eu (e alguns outros usuários aqui) venho martelando há algum tempo … Você pode sempre adicioná-lo à sua resposta, se desejar, e eu ‘ removerei o comente aqui (não ‘ não se esqueça de adicionar a chave faltando).

Resposta

Não consigo “pensar em uma maneira de fazer isso usando grep; ^ em si é parte de um expressão regular, portanto, usá-la requer que expressões regulares sejam interpretadas. É trivial usar correspondência de substring em awk, perl ou qualquer outra coisa:

awk -v search="$1" "substr($0, 1, length(search)) == search { print }" 

Para lidar com strings de pesquisa contendo \, você pode usar o mesmo truque de Resposta de 123 “:

search="$1" awk "substr($0, 1, length(ENVIRON["search"])) == ENVIRON["search"] { print }" 

Comentários

  • Isso não ‘ funcionará para strings como como \/
  • @ 123 na verdade, eu ‘ adicionei uma variante para lidar com isso.
  • Ainda falhará para strings complicadas como \\\/\/\/\\\\/ que é visto como \\///\\/ no programa. Pelo que eu sei, não há como escapar adequadamente das barras invertidas no awk, a menos que você saiba quantas serão usadas de antemão.
  • @ 123 obrigado, I ‘ adaptei seu truque de examinar o ambiente para evitar o processamento de escape.
  • Ainda gosto mais dessa solução. Eficiente (awk + nenhum tempo perdido olhando ao redor), a inicialização rápida (awk + nenhum processo adicional necessário para configurar o estado) usa ferramentas padrão e é bastante conciso. Todas as outras respostas carecem de pelo menos algumas delas. (Eficiência é um ponto forte aqui, já que grep é conhecido por sua velocidade incomparável.)

Resposta

Se você apenas precisa verificar se uma correspondência foi encontrada ou não, corte todas as linhas de entrada para o comprimento do prefixo desejado ($1) e use grep de padrão fixo:

if cut -c 1-"${#1}" | grep -qF "$1"; then echo "found" else echo "not found" fi 

Também é fácil obter a contagem das linhas correspondentes:

cut -c 1-"${#1}" | grep -cF "$1" 

Ou os números das linhas de todas as linhas correspondentes (os números das linhas começam em 1):

cut -c 1-"${#1}" | grep -nF "$1" | cut -d : -f 1 

Você pode alimentar os números das linhas para head e tail para obter o texto completo das linhas correspondentes, mas nesse ponto é mais fácil obter apenas uma linguagem de script moderna como Python ou Ruby.

(Os exemplos acima assumem Posix grep e cut. Eles assumem que o arquivo a ser pesquisado vem da entrada padrão, mas pode ser facilmente adaptado para receber um nome de arquivo.)

Editar: Você também deve garantir que o padrão ( $1) não é uma string de comprimento zero. Caso contrário, cut falhará dizendo values may not include zero. Além disso, se estiver usando Bash, use set -o pipefail para detectar saídas de erro por cut.

Resposta

Uma maneira de usar perl que respeitará as barras invertidas

v="$1" perl -ne "print if index($_, $ENV{"v"} )==0" file 

Isso define a variável de ambiente v para o comando, então imprime se o índice da variável é 0, ou seja, o início da linha.

Você também pode fazer o mesmo no awk

v="$1" awk "index($0, ENVIRON["v"])==1" file 

Resposta

Esta é uma opção totalmente bash, não que eu recomende o bash para processamento de texto, mas funciona.

#!/usr/bin/env bash # searches for $1 at the beginning of the line of its input len=${#1} while IFS= read -r line do [[ "${line:0:len}" = "$1" ]] && printf "%s\n" "$line" done 

O script calcula o comprimento len do parâmetro inserido $ 1 e usa a expansão do parâmetro em cada linha para ver se os primeiros len caracteres correspondem a $ 1. Se sim, imprime a linha.

Resposta

Se seu $1 for ASCII puro e seu grep tem a opção -P (para habilitar PCRE), você pode fazer isso:

 #!/bin/bash line_start="$1" line_start_raw=$(printf "%s" "$line_start" | od -v -t x1 -An) line_start_hex=$(printf "\\x%s" $line_start_raw) grep -P "^$line_start_hex"  

A ideia aqui é que grep -P permite expressões regulares com \xXX para especificar caracteres literais, onde XX é o valor ASCII hexadecimal desse caractere. O caractere er é correspondido literalmente, mesmo que seja um caractere regex especial.

od é usado para converter o início da linha esperado em uma lista de valores hexadecimais, que são então encadeados, cada um prefixado com \x por printf. ^ é então anexado a esta string para construir o regex necessário.


Se o seu $1 for unicode, então isso se torna um pouco mais difícil, porque não há uma correspondência 1: 1 de caracteres para bytes hexadecimais conforme a saída de od.

Resposta

Se seu grep tiver a opção -P, o que significa PCRE , você pode fazer isso:

grep -P "^\Q$1\E" 

Consulte esta pergunta , e consulte o documento PCRE para obter detalhes, se desejar.

Resposta

Como um filtro:

perl -ne "BEGIN {$pat = shift} print if /^\Q$pat/" search-pattern 

Execute em um ou mais arquivos:

perl -ne "BEGIN {$pat = shift} print if /^\Q$pat/" search-pattern file.. 

A seção “Quoting metacaracteres” da documentação perlre explica:

Citando metacaracteres

Metacaracteres com barra invertida em P erl são alfanuméricos, como \b, \w, \n. Ao contrário de algumas outras linguagens de expressão regular, não há símbolos de barra invertida que não sejam alfanuméricos. Portanto, qualquer coisa que se pareça com \\, \(, \), \[, \], \{ ou \} é sempre interpretado como um personagem literal, não um metacaractere. Isso já foi usado em um idioma comum para desativar ou citar os significados especiais dos metacaracteres de expressão regular em uma string que você deseja usar como padrão. Basta citar todos os caracteres que não sejam de “palavras”:

 $pattern =~ s/(\W)/\\$1/g; 

(Se use locale estiver definido, isso depende de o local atual.) Hoje é mais comum usar a função quotemeta ou a \Q sequência de escape de metaquitação para desativar os significados especiais de todos os metacaracteres como este:

 /$unquoted\Q$quoted\E$unquoted/ 

Cuidado se você colocar barras invertidas literais (aquelas que não estão dentro de variáveis interpoladas) entre \Q e \E, a interpolação de barra invertida com aspas duplas pode levar a resultados confusos. Se você precisar usar barras invertidas literais em \Q...\E, consulte “Detalhes sangrentos de análise de construções citadas” em perlop .

quotemeta e \Q são totalmente descritos em quotemeta .

Resposta

Se houver um personagem que você usa “t use, você pode usar isso para marcar o início da linha. Por exemplo, $"\a" (ASCII 007). É feio, mas vai funcionar:

{ echo "this is a line to match"; echo "but this is not"; } >file.txt stuffing=$"\a" # Guaranteed never to appear in your source text required="this" # What we want to match that beginning of a line match=$(sed "s/^/$stuffing/" file.txt | grep -F "$stuffing$required" | sed "s/^$stuffing//") if [[ -n "$match" ]] then echo "Yay. We have a match: $match" fi 

Se você não precisa das linhas correspondentes, pode descartar a sed final e usar grep -qF. Mas é muito mais fácil com awk (ou perl) …

Resposta

Quando você deseja olhar em um arquivo sem um loop, você pode usar:
Corte o arquivo com o comprimento da pesquisa string

Procure strings fixas e retorne os números das linhas

 grep -Fn "$1" <(cut -c1-${#1} < file) 

Use os números das linhas para algo como sed -n "3p;11p" file

 sed -n "$(grep -Fn "$1" <(cut -c1-${#1} < file) | sed "s/:.*/p;/" | tr -d "\n")" file 

Quando quiser excluir essas linhas, use

 sed "$(grep -Fn "$1" <(cut -c1-${#1} < file) | sed "s/:.*/d;/" | tr -d "\n")" file 

Deixe uma resposta

O seu endereço de email não será publicado. Campos obrigatórios marcados com *