Preciso descobrir qual é o número da linha da primeira ocorrência de uma determinada string de pesquisa que deve estar no início de uma linha em um arquivo de texto e armazená-la em uma variável no meu script bash. Por exemplo, quero encontrar a primeira ocorrência de "c":
abc
bde
cddefefef // this is the line that I need its line number
Casdasd // C here is capital, I dont need it
azczxczxc
b223r23r2fe
Cssdfsdfsdf
dccccdcdcCCDcdccCCC
eCCCCCC
Eu inventei isso, mas como você vê, há grandes problemas
trimLineNum=$(cat "${varFileLog}" | grep -m1 -n "c")
echo "c is at line #"${trimLineNum}
A saída será:
c is at line #1:abc
Problemas:
- Então, obviamente, corresponde à primeira linha, porque há um "c" na linha.
- A saída também incluirá o conteúdo da linha! Eu quero que seja apenas o número da linha
o que devo mudar para corrigir esses problemas?
Com POSIX
sed
, você suprime a saída normal com a-n
opção, então para a linha que começa comc
(pattern^c
), imprima o número da linha com=
eq
uit:Com GNU
sed
, você pode usar oQ
comando para sair sem saída e simplificar paraExistem várias soluções
com AWK
/^c/
: corresponde à linha que começa comc
print NR
: imprime o número do registro (linha)exit
: não continua o processamentoComo eu gosto
awk
, esta é a minha solução preferidacom grep + filtragem
'^c'
: corresponde à linha que começa comc
head -1
: exibe apenas a primeira linha dos resultados do grepsed 's/:.*//'
: remove qualquer coisa após o:
sed 's/:.*//'
ecut -d: -f1
ter o mesmo efeito nesse casosobre desempenho
Isso pode ser mais lento que a solução de Stephen:
Você precisa informar
grep
sobre sua restrição “isso deve estar no início de uma linha”, ancorando a correspondência no início de uma linha com^
:Em seguida, a saída do pós-processamento
grep
para manter apenas o número da linha:Observe que
-m
é uma extensão GNU (e com GNUgrep
, você precisa,--
mesmo que^c
não comece com--
, caso o$varFileLog
próprio-
GNUgrep
aceite opções mesmo após argumentos não opcionais). Normalmente, você pode canalizar a saída parahead -n 1
.Se não houver correspondência, o primeiro comando retornará false/failure, enquanto o segundo sempre retornará true, a menos que você ative a
pipefail
opção como suportada por vários shells, incluindobash
.grep pode imprimir o número da linha de uma correspondência com
-n
ou--line-number
então você pode usar isso.O problema então se reduz a:
Você pode fazer o primeiro com
head
e o segundo comcut
:Em sua saída de exemplo, você tem algum texto extra - não tenho certeza se isso é importante para você ou não. No entanto, quando você tem um número em STDOUT, adicionar algum prefixo de string a isso é uma tarefa simples, e deixarei isso para você.
Usando Raku (anteriormente conhecido como Perl_6)
OU
OU
Saídas:
-ne
Os sinalizadores de linha de comando do Raku (sem impressão automática em linhas) são usados. Para obter o número da linha, umastate
variável$i
é inicializada uma vez e depois incrementada para cada linha lida. Onde um "c" de início de linha é identificado (por regex, ouindex
, oustarts-with
), a string"c starts line $i"
é interpolada e saída (say
).Nota: a condicional de baixa precedência
as last
é adicionada a cada exemplo acima. Remova essa condicional para retornar todos os números de linha correspondentes, por exemplo:Adendo: Graças a esta resposta SO , aqui está uma maneira rápida de obter o primeiro número de linha indexado a zero começando com "c" usando a
first
rotina do Raku:Entrada de amostra:
https://raku.org