Estou tentando obter uma linha específica de um arquivo de texto.
Até agora, online eu só vi coisas como sed, (eu só posso usar sh -não bash ou sed ou algo parecido). Preciso fazer isso usando apenas um script de shell básico.
cat file | while read line
do
#do something
done
Eu sei como iterar pelas linhas, conforme mostrado acima, mas e se eu só precisar obter o conteúdo de uma linha específica
cat
tudo bem, massed
não está? Isso não faz sentido.cat
. Aw ... fofocat
!Respostas:
sed:
awk:
fonte
5!d
significa excluir todas as linhas, exceto 5. shell var é possível, você precisa de aspas duplas.sed -n 5p
Isso parece mais lógico de lembrar para iniciantes, porque-n
significa "sem saída por padrão" ep
significa "imprimir", e não há menção potencialmente confusa de exclusão (quando as pessoas falam de arquivos, excluir linhas tende a significa algo diferente).-n '5p'
trabalha para esse problema também. A diferença aqui é que5!d
você pode adicionar-i
para gravar a alteração de volta no arquivo. no entanto, com-n 5p
vocêsed -n '5p' f > f2&& mv f2 f
novamente, para esta questão, concordo com sua opinião.Assumindo que
line
é uma variável que contém o número da linha necessária, se você pode usarhead
etail
, é bastante simples:Caso contrário, isso deve funcionar:
fonte
-eq
comparação é para inteiros, portanto, ela quer um número de linha, não o conteúdo da linha ($line
). Isso deve ser corrigido definindo, por exemplo,want=5
antes do loop e, em seguida, usando a-eq
comparação ativada$want
. [mudou de uma edição rejeitada]Você poderia usar
sed -n 5p file
.Você também pode obter um intervalo, por exemplo
sed -n 5,10p file
,.fonte
Melhor método de desempenho
Porque
sed
para de ler qualquer linha após a 5ªAtualizar experimento do Sr. Roger Dueck
fonte
sed -n 5q
sed
para de ler qualquer linha após a 5ª.sed -n 1p /usr/share/dict/words
esed '1q;d' /usr/share/dict/words
usando otime
comando; o primeiro levou 0,043s, o segundo apenas 0,002s, então usar 'q' é definitivamente uma melhoria de desempenho!Se, por exemplo, você deseja obter as linhas 10 a 20 de um arquivo, pode usar cada um destes dois métodos:
ou
p
no comando acima significa impressão.Aqui está o que você verá:
fonte
A maneira padrão de fazer esse tipo de coisa é usar ferramentas externas. Não permitir o uso de ferramentas externas ao escrever um script de shell é um absurdo. No entanto, se você realmente não deseja usar ferramentas externas, pode imprimir a linha 5 com:
Observe que isso imprimirá a linha lógica 5. Ou seja, se
input-file
contiver continuações de linha, elas serão contadas como uma única linha. Você pode alterar esse comportamento adicionando-r
ao comando de leitura. (Que provavelmente é o comportamento desejado.)fonte
$((++i))
parece ser um bashismo; se o OP está restrito ao uso de ferramentas externas, eu não presumiria que eles teriam acesso a mais do que um plano/bin/sh
++
incrementos é especificamente marcado como opcional).$((i+=1))
funciona no Dash, também.$(($i+1))
é a solução alternativa simples que eu estava pensando.Em paralelo com a resposta de William Pursell , aqui está uma construção simples que deve funcionar até mesmo no shell Bourne v7 original (e, portanto, também em locais onde o Bash não está disponível).
Observe também a otimização para
break
sair do loop quando obtivemos a linha que procurávamos.fonte
Eu particularmente não gostei de nenhuma das respostas.
Aqui está como eu fiz.
fonte
Fácil com perl! Se você deseja obter as linhas 1, 3 e 5 de um arquivo, diga / etc / passwd:
fonte
seq 5 | perl -ne 'print if $. ~~ [1, 4, 5]'
mas o smartmatch é experimental e seu uso desencorajadofonte
sed -n 5p
que, claro, ainda pode ser otimizado para algo comosed -n '5!d;p;q'