4

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?

  • I want to print new line after specific pattern like (00:00) or (12:05) or ...etc – user90704 Sep 9 '18 at 22:35
  • 3
    1 is relatively straightforward, but even if you repeated the for loop again, then it would print out the previous lines again. You'd have to save the previous output in a buffer somehow, and not show them again. Or use -s and save the current time? Also, the output of last is reverse chronological, so the additional runs would be all out of order. – Sparhawk Sep 9 '18 at 22:38
  • 2
    The list from the output of the command last will be updated every time someone ssh a computer on network. i want to repeat for loop again and again and again and again and again and again and again and again and again and again and again and again and again and again and again and again and ……. etc. How can I do it? ;-) – user90704 Sep 9 '18 at 22:42
  • Useless use of backticks. – David Foerster Sep 10 '18 at 9:49
7

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.

2

You can use if .. then statement something like:

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

If you would like to repeat for loop in a bash to read the output of a command (in your example, the command last), then you have to schedule the script in crontab. More clarifications are here.

0

You can have different approaches and we need you to describe the NEED you have (identify a specific person's login? identify who was loggued as a specific time? etc)

With just what you said (adding a newline when something shows up in last), you already have different approaches:

#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?" }
  '

etc.

You could also look for apparitions in log files

You could also insert some command in /etc/profile (beware as it can have lots of security implications, and also may create problems at boot, at init launch, etc. It would be an ugly hack, could wreak several (or all) user's login, and could anyway be bypassed by fast pressing of ctrl-C by the one logging in...)

Etc, etc. Many ways to go, and the best one will be the one fixing what you need to do, and now necessarily sticking to "last" and "adding a newline when I see something in it"

For better answers, please give us really what you NEED, and WHY you need it, and not HOW you think you need to do this or that action (add a newline when you see an output of last? Why do you think you need to do that? what is the underlying need?)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy