Executar um comando (por exemplo, começar uma nova linha) ao ler uma string específica dentro de uma palavra

3

Quando um script está lendo um arquivo de texto, eu gostaria que esse código executasse um comando específico quando ele encontrasse uma string específica dentro de uma variável específica.

Exemplo:

Digamos que eu gostaria de usar o seguinte código para ler a saída do comando last :

#!/bin/bash
for i in 'last'; do 
  sleep 0.1 | echo -ne "$i " 
done

A saída do comando last é uma tabela na forma de uma lista de entradas, algo como:

username  pts/2        1.2.3.4 via  Sun Sep  2 06:40 - 06:40  (00:00)
. . . . 
. . . . 
  1. A variável i no código anterior pode ser qualquer frase na tabela anterior. Eu gostaria de aplicar um comando específico e. g. inicie uma nova linha quando o código encontrar uma string específica dentro da variável i , por exemplo quando a variável i contiver um parêntese fechado ) Eu quero que o código inicie uma nova linha. / p>

  2. Quando o código terminar de ler a saída do comando last , eu quero que o código repita o loop para mais uma vez (várias vezes) para ler se houver novas atualizações . Como posso direcionar o código para ser executado novamente? Por exemplo, existe tal comando goto que forçará o código a ir para a linha específica?

Você poderia por favor conselho?

    
por David Foerster 10.09.2018 / 00:20

3 respostas

7

Se a saída do seu last for assim:

username  pts/2        1.2.3.4 via  Sun Sep  2 06:40 - 06:40  (00:00)

e você deseja adicionar as novas linhas onde elas estavam originalmente, sugiro alterar um pouco a lógica. Leia a entrada linha por linha para começar e divida a linha em palavras somente depois disso. Dessa forma, não há necessidade de procurar explicitamente os parênteses. E você pode repetir todo o loop colocando-o dentro de while true; do ... done . Então, temos algo assim:

#!/bin/bash
set -f
while true; do
        last | while IFS= read -r line; do
                for word in $line; do
                        sleep .1
                        printf "%s " "$word"
                done
                echo     # prints a newline
        done
done

set -f desativa a expansão de nome de arquivo, o que, de outra forma, possivelmente aconteceria na expansão sem aspas de $line . Além disso, eu usaria printf em vez de eco para imprimir as palavras, por várias razões.

Se você quiser explicitamente procurar pelo parêntese de fechamento, poderá usar o [[ .. ]] test: ele permite a correspondência de padrões com padrões semelhantes a glob, ou com regexes. ( [[ $word =~ $re ]] seria a correspondência de expressão regular)

#!/bin/bash
set -f
while true; do
        for word in $(last); do
                sleep .1
                printf "%s " "$word"
                [[ $word = *')'* ]] && echo
        done
done

Embora este, é claro, não adicione uma nova linha nas linhas em que a duração final do login é substituída por algo como still logged in .

A construção for word in $whatever tem a desvantagem de tratar vários espaços exatamente como espaços simples, portanto, a saída do script não terá as colunas alinhadas tão perfeitamente quanto no original.

    
por 10.09.2018 / 00:47
2

Você pode usar a declaração if .. then como:

#!/bin/bash
for i in 'last'; do 
    sleep 0.1 | echo -ne "$i " 
     if [[ $i = *')'* ]] ; then 
       echo "" ; 
     fi
done

Se você quiser repetir for loop em um bash para ler a saída de um comando (no seu exemplo, o comando last ), será necessário programar o script em crontab . Mais esclarecimentos são aqui .

    
por 10.09.2018 / 01:18
0

Você pode ter diferentes abordagens e precisamos que você descreva a NECESSIDADE que você tem (identifique o login de uma pessoa específica? identifique quem foi logado como um horário específico? etc)

Com o que você disse (adicionando uma nova linha quando algo aparece por último), você já tem abordagens diferentes:

#finding if a 'last' line contains a "specific_thing" (which is itself a regular expression...) 
# and can print all lines or not depending on showall value
while true ; do
  last | awk -v looking_for="specific_thing" -v showall=0 '
    ( showall == 1 )     { print $0 }
    ( $0 ~ looking_for ) { action="print line? and add something to it?" }
  '
done

#watch for new things appearing in last and not the whole "last" output every time
watch last | awk -v looking_for="specific_thing" -v showall=0 '
    ( showall == 1 )     { print $0 }
    ( $0 ~ looking_for ) { action="print the line? with added infos?"
                           action="execute : system(some command) ?"
                           action="all of that?" }
  '

Você também pode procurar por aparições em arquivos de log

Você também pode inserir algum comando em / etc / profile (cuidado, pois pode ter muitas implicações de segurança, e também pode criar problemas na inicialização, no lançamento do init, etc. Seria um hack feio, poderia causar vários problemas ( ou todos) o login do usuário, e poderia de qualquer forma ser contornado pressionando rapidamente ctrl-C por um login ...)

Etc, etc. Muitos caminhos a percorrer, e o melhor deles será aquele que vai consertar o que você precisa fazer, e agora necessariamente se prendendo a "último" e "adicionando uma nova linha quando eu vejo algo nele"

Para melhores respostas, por favor, dê-nos realmente o que você precisa, e por que você precisa, e não COMO você acha que precisa fazer isso ou aquilo (adicione uma nova linha quando vir uma saída? Por que você acha você precisa fazer isso? Qual é a necessidade subjacente?)

    
por 10.09.2018 / 16:18