LinuxQuestions.org
Visit Jeremy's Blog.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 06-01-2013, 08:35 PM   #1
cin_
Member
 
Registered: Dec 2010
Posts: 281

Rep: Reputation: 24
Bash :: Retrieving Output From A Command Streaming Information


That title is strained... difficult to describe my interest, even more so to do it in a pithy manner.

basically I am running a command called aseqdump. From the man page:
Code:
NAME
       aseqdump - show the events received at an ALSA sequencer port

SYNOPSIS
       aseqdump [-p client : port,...]
When running the program listens to a client and outputs the clients status.
In my usage I am listening to a midi device.
The output constantly refreshes.

I am trying to write a bash script that reads in the most recent line and works off the information from that last line.
How can I do this?

I have tried to set the output as a variable, but was having difficulty making this work the way I intended.

Then I piped the output to a file and read from the file, which worked fine but the file quickly filled up, so I tried to cat only the last ten lines of the file back into itself but this crashed the pipe.

In the end I wrote a separate script that determines the number of lines in the output file, if it exceeds an upper limit it kills the process, cats the last ten lines into itself, then restarts the command with an appending pipe. Then it waits and does it again when needed.
This final method is just chewing up resources. About 8% when running and 17% and 14% when idling.

All I want is to read the latest output from a running command.
How can I do what I want to do without sucking up so much CPU?

Last edited by cin_; 06-01-2013 at 08:37 PM. Reason: gramm`err
 
Old 06-01-2013, 11:52 PM   #2
ntubski
Senior Member
 
Registered: Nov 2005
Distribution: Debian, Arch
Posts: 3,780

Rep: Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081
Quote:
Originally Posted by cin_ View Post
I am trying to write a bash script that reads in the most recent line and works off the information from that last line.
Every line is the most recent line... at the time it's output. Maybe you want something like: skip lines when there is more data available within the next second. But also consider telling us what the actual problem is.

Code:
#!/bin/bash

# invoke as 
#   aseqdump | ./latest-line.bash

while read line ; do
    while read -t 1 newline ; do
        line=$newline
    done

    echo "the latest line is: $line"
done
 
Old 06-02-2013, 06:45 AM   #3
David the H.
Bash Guru
 
Registered: Jun 2004
Location: Osaka, Japan
Distribution: Arch + Xfce
Posts: 6,852

Rep: Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037
Yes, more info please. How about showing us an actual example of the output, and what you want to get from it?

You may be able to simply run the command directly into sed or awk or similar, depending on your exact desires.
 
Old 06-03-2013, 01:24 AM   #4
cin_
Member
 
Registered: Dec 2010
Posts: 281

Original Poster
Rep: Reputation: 24
Figured

ntubski, David the H., thanks for the reply...

My problem the whole time was my ignorance in relation to viewing piping as an input.

I always associate the pipe with output, as if it were a one sided connection.
I used pipes to direct output.

But, of course, you are directing it somewhere and that place you are piping it to is using it as input.
This is the first time in a program I have used, or even thought to use, stdin.

stdin fixed the issue perfectly.

I was writing a naive program to turn my midi keyboard into a type keyboard input device.
The script serves its purpose, especially now that I have the resource consumption running at zero, but the function of it turned out to be a way better idea than I had anticipated.
Now I program with my electronic keyboard, and if I hit a snag or am just burned on repetitious code, I turn up the piano and just play until I am able to work again.


nutes...
Code:
#!/bin/bash

while [ 17 ]; do
olea=""

aseqdump -p 20 | {

while read line ; do

	a=($line)
	if [ "$olea" != "$line" ];then
		
		b=${a[5]}
		if [ $b ]; then
						lenny=${#b}
						last=${b:$lenny-1:$lenny}
						if [ "$last" == "," ]; then
							b=${b:0:$lenny-1}
						fi
		fi
		c=${a[4]}
		case "$b" in

			#7h3 0c74v35
			"60") if [ "${a[2]}" == "on" ]; then `/root/pikey/./xsendkeycode 54 1`; else `/root/pikey/./xsendkeycode 54 0`;fi;; #echo -ne "c"; echo -ne "c">>textfile ;;
			"62") if [ "${a[2]}" == "on" ]; then `/root/pikey/./xsendkeycode 40 1`; else `/root/pikey/./xsendkeycode 40 0`;fi;; #echo -ne "d"; echo -ne "d">>textfile ;;
			"64")	if [ "$c" == "controller" ]; then 
								valdue=${a[7]}
								if [ "$valdue" == "127" ]; then 
									`/root/pikey/./xsendkeycode 62 1` #shft
								else	
									`/root/pikey/./xsendkeycode 62 0` #shft
								fi
							else 
								if [ "${a[2]}" == "on" ]; then 
									`/root/pikey/./xsendkeycode 26 1` 
								else 
									`/root/pikey/./xsendkeycode 26 0`
								fi
										#echo -ne "e"
										#echo -ne "e">>textfile 
						fi;;
			"65") if [ "${a[2]}" == "on" ]; then `/root/pikey/./xsendkeycode 41 1`; else `/root/pikey/./xsendkeycode 41 0`;fi;; #echo -ne "f"; echo -ne "f">>textfile ;;
			"67") if [ "${a[2]}" == "on" ]; then `/root/pikey/./xsendkeycode 42 1`; else `/root/pikey/./xsendkeycode 42 0`;fi;; #echo -ne "g"; echo -ne "g">>textfile ;;
			"69") if [ "${a[2]}" == "on" ]; then `/root/pikey/./xsendkeycode 38 1`; else `/root/pikey/./xsendkeycode 38 0`;fi;; #echo -ne "a"; echo -ne "a">>textfile ;;
			"71") if [ "${a[2]}" == "on" ]; then `/root/pikey/./xsendkeycode 56 1`; else `/root/pikey/./xsendkeycode 56 0`;fi;; #echo -ne "b"; echo -ne "b">>textfile ;;

						
		

		esac
	fi

	olea="$line"

done
}
done
It makes for net positive distractions.

Last edited by cin_; 06-03-2013 at 10:12 AM. Reason: gramm`err
 
Old 06-03-2013, 04:14 PM   #5
David the H.
Bash Guru
 
Registered: Jun 2004
Location: Osaka, Japan
Distribution: Arch + Xfce
Posts: 6,852

Rep: Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037
I'm glad we could help you figure it out.

However, now I'd like to comment on your script. There are some improvements we could make to it. First some general advice:

1) When using advanced shells like bash or ksh, it's recommended to use [[..]] for string/file tests, and ((..)) for numerical tests. Avoid using the old [..] test unless you specifically need POSIX-style portability.

http://mywiki.wooledge.org/BashFAQ/031
http://mywiki.wooledge.org/ArithmeticExpression

2) $(..) is highly recommended over `..`

3) process substitution is usually better than a pipe for feeding a while loop.

4) Your formatting could be more consistent, and a few comments explaining what the code is doing would help make it more understandable.

Now for a few specific lines:

5)
Code:
while [ 17 ]; do
What's the "17" for? All this does is return as always true, so the loop never ends. If you want a continuous loop, then just use "while true", with true being the shell built-in command.

But I question whether this loop is even necessary. The inner loop should continue to run for as long as the input doesn't issue an EOF. Of course I don't know anything about the aseqdump command, so perhaps it does.

6)
Code:
a=($line)
I thought about combining this array-setting line with the outside loop, and just using read -a there. But then again I don't know what the exact input line format looks like, so I decided it would be better to keep it this way. But it's still safer to use read to break up the line than to rely on direct shell word-splitting. You don't have to leave the variable unquoted that way.

7)
Code:
b=${a[5]}
if [ $b ]; then
    lenny=${#b}
    last=${b:$lenny-1:$lenny}
    if [ "$last" == "," ]; then
        b=${b:0:$lenny-1}
    fi
fi
The nearest I can deduce, the only purpose of this is to remove any possible trailing commas (an example of how comments help out). If so, you've made it ten times more complex than it has to be. A single parameter substitution is all that's required to do that.

8)
Code:
"60") if [ "${a[2]}" == "on" ]; then `/root/pikey/./xsendkeycode 54 1`; else `/root/pikey/./xsendkeycode 54 0`;fi;; #echo -ne "c"; echo -ne "c">>textfile ;;
Several problems here, starting with formatting. Idividual commands should generally be kept on separate lines. There's no shortage of space in a shell script.

But more to the point, You use the same basic code over and over inside the case statement, making it a perfect candidate for a shell function. Write once, use many, and help keep the code clean.

Third, you're running the commands inside `..` brackets. In addition to suggestion #2 above, I can't see how this would even work. command substitutions like this are replaced with the text output of the command, and then the shell attempts to execute that line. So, unless the text expands into a valid command, it shouldn't work at all. I think you just want to leave them off.

Finally, the extra "/./" in the command path is kind of pointless and ugly. Not that it really hurts anything though.


So anyway, here's my attempt at a revised version of the script. I didn't try to change anything major in the way it functioned, but only tried to reorganize it in a clearer fashion. I can't guarantee that I got everything right, since I don't know what the input looks like or for that matter anything else about it what it's rally doing. But hopefully you can work around any errors.

Code:
#!/bin/bash

outfile=textfile
PATH="/root/pikey:$PATH"

f_sendkey() {
    case ${a[2]} in
        on) xsendkeycode "$1" 1 ;;
         *) xsendkeycode "$1" 0 ;;
    esac
    #echo -ne "$2" >>"$outfile"
}

while true; do
    olea=""

    while read -r line ; do

        if [[ $olea != $line ]]; then
          
            read -ra a <<<"$line"
            b=${a[5]%,}
            c=${a[4]}
            
            case "$b" in

                60) f_sendkey 54 c  ;;
                62) f_sendkey 40 d  ;;
                65) f_sendkey 41 f  ;;
                67) f_sendkey 42 g  ;;
                69) f_sendkey 38 a  ;;
                71) f_sendkey 56 b  ;;
                64) if [[ $c == controller && ${a[7]} -eq 127 ]]; then 
                        xsendkeycode 62 1
                    elif [[ $c == controller ]]; then
                        xsendkeycode 62 0
                    else 
                        f_sendkey 26 e
                    fi
                    ;;     

            esac
        fi

        olea=$line

    done < <( aseqdump -p 20 )

done

exit 0

Last edited by David the H.; 06-03-2013 at 04:27 PM. Reason: minor wording changes
 
Old 06-04-2013, 03:32 AM   #6
cin_
Member
 
Registered: Dec 2010
Posts: 281

Original Poster
Rep: Reputation: 24
David the H., good stuff...

(1, 2, 3, 7) again, all new to me. I'll definitely use these in the future. I am really enjoying these parameter and process substitutions.

(4) fair enough, though this was just a rough sketch.

(5) ha, the 17... yeah that'll have to stay. I know what its intended meaning is. 17 is just something I do.

As for the necessity of the loop... it is, because of how I use the script. Basically if you run the program without the keyboard plugged in and turned on then aseqdump EOFs on you, so this outer loop keeps running the program in anticipation that at some time it will run it and the keyboard will be there to communicate with. So I can unplug, bring my laptop to work, return home, plug back in, and everything works fine.

(6) I was elsewhere suggested to use the 'read -r' and so I tried to find some literature on the different parameters for read and came up short. I tried man read, but the information was sparse.

(8) yeah, some of these issues: using a function, the path to the separate commands; I already intended on cleaning up, and had done so after my last post.


Your clean up work is nice. Again, those parameter and process substitutions are choice.
Just seems to be missing the initial 'while (( 17 ));do', but its okay... you'll get there.


I kid. Seriously though, thank you for the education.

Last edited by cin_; 06-04-2013 at 03:34 AM. Reason: gramm`err
 
Old 06-04-2013, 12:59 PM   #7
David the H.
Bash Guru
 
Registered: Jun 2004
Location: Osaka, Japan
Distribution: Arch + Xfce
Posts: 6,852

Rep: Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037
I'm always glad to help out. You're doing a pretty good job so far. Just keep working at it.

read is a shell built-in, as it has to be in order to set variables directly. So you need to look at your shell's documentation (i.e. man bash) instead. man read is for the C programming language function of the same name.

You can type help to get a list of all bash built-ins, and type <command> will tell you what your shell is using for any specific command name.
 
  


Reply

Tags
bash



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
Retrieving and Organizing Data from Command Output resuni Programming 3 03-31-2011 07:28 PM
finger command's output and user's information Hi_This_is_Dev Linux - Server 1 10-03-2009 06:51 AM
retrieving hardware information from linux servers ginorocca Linux - Hardware 1 05-20-2009 07:09 AM
how to get the absolute path information of a command from ps command output ratul_11 Linux - General 1 08-06-2008 02:10 AM
what is a bash command to found out information about computer stats whited Linux - Hardware 1 06-20-2007 09:49 AM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 04:10 PM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration