Observe que, exceto pelo código adicional na tentativa 2, todo o código realmente faz o oposto do que o OP fez. Como você pode ver na tentativa 2, é fácil adaptar os comandos.
Eu tinha um arquivo de texto com 1.108.752 linhas, com cerca de 83 MB de tamanho. Eu queria obter 46.744 linhas, variando entre a 15ª e a 1.108.716ª linha, que é em média a cada 24 linhas.
tl; dr;
A segunda tentativa é mais rápida que a primeira. Terceiro só funciona para menos linhas.
Primeira tentativa (ruim)
Para cada linha que eu quero, sed
lê linhas do início do arquivo de texto, mas não as imprime ( -n
). Quando atingir a linha que quero, imprima-a ( p
), depois feche ( q
) em vez de ler até o final do arquivo. Então faça isso novamente para o próximo linenumber.
Obviamente, isso leva um pouco mais de tempo a cada execução, porque sed
precisa passar por mais linhas do que antes de cada vez.
Se eu calculei isso direito, no meu caso, isso levaria cerca de 307332472188 passa pelo arquivo de texto geral. Oh meu.
Observe que, para essa abordagem, a ordem das linhas é irrelevante no arquivo linenumbers:
while read line; do
sed -n "${line}{p;q}" "${INFILE}"
done
Resultados da temporização: 2568.80s user 256.10s system 92% cpu 51:00.37 total
. Não é bom.
Segunda tentativa (melhor)
Isso lê os linenumbers do arquivo e acrescenta um p
(novamente, para imprimir esta linha). Essa cadeia é canalizada para o próximo sed
, que lê de um arquivo ( -f
), que aqui é STDIN
escrito como -
, que é a saída do primeiro sed
, que é realmente o linenumber a ser impresso:
sed 's/$/p/' "${LINENUMS}" | sed -n -f - "${INFILE}"
Resultados da temporização: 146.54s user 0.18s system 100% cpu 2:26.70 total
. Muito bom!
Se você quiser não imprimir as linhas do linefile (como OP queria fazer), altere ligeiramente o comando para que os linenumbers sejam d eletizados em vez de < em> p , e imprime todas as outras linhas em vez de excluí-las (-n):
sed 's/$/d/' "${LINENUMS}" | sed -f - "${INFILE}"
Terceira tentativa (mais ruim)
Isso não funcionou para mim porque eu tinha muitas linhas que queria extrair. Deve funcionar para (muito) menos linhas, mas não sei o limite para isso.
Eu tentei criar uma longa string para sed, o que eu esperava que levasse a sed
passando pelo arquivo apenas uma vez (!), não imprimindo nada exceto os linenumbers da string:
sed -n "12p;15p;24p;345p;...;12345;" ${INFILE}"
mas isso resultaria em uma string com cerca de 420076
caracteres, que após bombear para sed
simplesmente levou a sed: Argument list is too long
. O que é compreensível.