Finalizar uma pesquisa de texto em menos (1) e continuar a ler através de um pipe Unix

5
gunzip < 100terabytes.txt.gz | less

less(1) lê quantas linhas forem necessárias para preencher sua tela e depois para read(2) . Como resultado, gunzip(1) é bloqueado em write(2) quando o canal fica cheio.

À medida que você rola para baixo, less(1) issues read(2) de novo e de novo, e conforme o canal é consumido, gunzip(1) tem permissão para emitir write(2) . Você tem total flexibilidade para ir e voltar aqui (supondo que gunzip < 100terabytes.txt.gz não seja concluído).

Tudo está bem até agora.

Você pode iniciar uma pesquisa de texto em less(1) com / . Porém, quando a string de pesquisa não é encontrada em 100terabytes.txt , less(1) deixa de responder. Você pode finalizar a pesquisa com Ctrl-C . Mas parece desligar o pipe entre gunzip(1) e less(1) . Eu não gosto disso. Eu quero rolar manualmente para baixo para consumir mais linhas de gunzip(1) depois que eu desista de uma pesquisa de texto. Isso é possível?

Não estou pedindo um conselho como gunzip < 100terabytes.txt.gz | grep pattern | less

Atualizar

Você pode experimentar com od -v /dev/zero | less

    
por nodakai 15.03.2016 / 06:53

2 respostas

3

Quando você pressiona Ctrl + C , todo o trabalho (grupo de processos) que recebe o SIGINT, less intercepta para abortar a pesquisa, mas gunzip terminará. Para evitar isso, você poderia fazer:

(trap '' INT; gunzip < file.gz) | less

para que gunzip ignore o SIGINT, mas note que você não poderá mais interromper gunzip depois disso.

Para gunzip , provavelmente está tudo bem, já que tudo que você precisa fazer é sair less , após o qual gunzip morrerá de um SIGPIPE da próxima vez que gravar algo, mas para aplicativos que simplesmente não exibem algo, isso seria mais um problema (você ainda seria capaz de usar Ctrl + Z para SIGTSTP ou Ctrl + \ para SIGQUIT).

Observe também que alguns comandos como pv ou ping instalam seu próprio manipulador SIGINT, o que reverteria nosso trap '' INT .

Você pode criar uma função para salvar digitando como:

iless() {
  (trap '' INT; "$@") | less
}

iless gunzip < file.gz

Ou:

noint() (trap '' INT; "$@")

noint gunzip < file.gz | less

Mas note que para:

gunzip < file.gz | grep foo | less

você precisaria escrever:

noint gunzip < file.gz | notint grep foo | less

ou:

noint eval 'gunzip < file.gz | grep foo' | less

ou:

iless eval 'gunzip < file.gz | grep foo'

Uma alternativa é usar a substituição do processo:

less -f <(gunzip < file.gz | grep foo)

ou (embora não em zsh ):

less < <(gunzip < file.gz | grep foo)

Nesses casos, o shell não inclui os comandos dentro da substituição do processo em um grupo de processos em primeiro plano (exceto no segundo caso para zsh ). Seu grupo de processos permanece o mesmo que o da shell. Isso significa que eles não recebem um SIGINT quando você pressiona Ctrl + C .

Note que esses processos não serão afetados por Ctrl + Z ou Ctrl + \ .

Testado em zsh , ksh93 e bash .

    
por 15.03.2016 / 17:37
0

Não é uma resposta exata, mas pode resolver o seu problema. De man less :

       ESC-F  Like  F,  but  as soon as a line is found which matches the last
              search pattern, the terminal bell is rung and forward  scrolling
              stops.

Isso pode ser interrompido por ^C , mas não sei se quebrará o pipe, porque não consegui reproduzir seu problema (acho que é necessário um arquivo de entrada muito grande para testar isso). Eu acho que não vai quebrar o pipe, porque normalmente você pode fazer repetidamente F então ^C em um arquivo crescente, e F ainda funciona (você ainda vê o arquivo crescendo).

O problema é: como inserir o "último padrão de pesquisa" sem congelar less se o padrão não for encontrado? Talvez a opção ^K para / ajude:

          ^K     Highlight any text which matches the pattern on the  cur-
                 rent screen, but don't move to the first match (KEEP cur-
                 rent position).

Editar: ou, mais simplesmente, use ? para "definir" esse "último padrão de pesquisa".

    
por 15.03.2016 / 11:02

Tags