Bash – Running a command (e.g. begin new line) when reading a specific string within a word

bashtext processing

When a script is reading text file I would like this code to run specific command when it finds a specific string within a specific variable.

Example:

Let's say that I would like to use the following code to read the output of the command last:

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

The output of the command last is a table in the form of a list of entries, something like:

username  pts/2        1.2.3.4 via  Sun Sep  2 06:40 - 06:40  (00:00)
. . . . 
. . . . 
  1. The variable i in the previous code can be any phrase in the previous table. I would like to apply a specific command e. g. begin new line when the code finds a specific string within the variable i, for example when the variable i contains a closed parenthesis ) I want the code to begin a new line.

  2. When the code finishes reading the output of the command last, I want the code to repeat the for loop once again (multiple times) to read if there are any new updates. How can I direct the code to re-run again? For example, is there such a command goto which will force the code to go to specific line?

Would you please advice?

Best Answer

If the output from your last is like this:

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

and you want to add the newlines where they originally were, then I would suggest changing the logic a bit. Read the input line-by-line to begin with, and split the line into words only after that. That way, there's no need to explicitly look for the parenthesis. And you can repeat the whole loop by wrapping it inside while true; do ... done. So we have something like this:

#!/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 disables filename expansion, which would otherwise possibly happen at the unquoted expansion of $line. Also, I'd use printf instead of echo to print the words, for a number of reasons.

If you do explicitly want to look for the closing parenthesis, then you can use the [[ .. ]] test: it allows for pattern matching with glob-like patterns, or with regexes. ([[ $word =~ $re ]] would be the regex match)

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

Though this one, of course, doesn't add a newline on lines where the final login duration is replaced by something like still logged in.

The for word in $whatever construct has the downside that it treats multiple spaces exactly like single spaces, so the output from the script will not have the columns aligned as neatly as in the original.

Related Question