LinuxQuestions.org
Review your favorite Linux distribution.
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 04-21-2010, 02:17 PM   #1
theaceoffire
LQ Newbie
 
Registered: Apr 2010
Posts: 4

Rep: Reputation: 0
Question How do I pass complicated commands (With bar's) as an argument to another script?


Ok, I have tried figuring out as much as I could on my own, but this is not as obvious as I hoped. I am attempting to script some tasks I have to do, but I have no control over one of the scripts I have to use... and they output all kinds of useless things on the screen.

My goal is simple: Capture all output from their scripts, and create a progress line that only shows the most recent output from their stuff.

So, here was my first solution; a file I called "spin":
Code:
#!/bin/bash
spinX(){
PROC=$1
STRT=`date "+%s"`
while [ -d /proc/$PROC ];do
        last3="`getLine $2`"
        echo -en "\r" "<(''<)   $last3";sleep 0.3
        last3="`getLine $2`"
        echo -en "\r" "<(' ')>  $last3";sleep 0.3
        last3="`getLine $2`"
        echo -en "\r" " (>'')>  $last3";sleep 0.3
        last3="`getLine $2`"
        echo -en "\r" "<(' ')>  $last3";sleep 0.3
done
END=`date "+%s"`
Finished=`printf "%02d:%02d:%02d" $((($END-$STRT)/3600)) $((($END-$STRT)/60%60)) $((($END-$STRT)%60))`
echo -en "\r" "(^-^) Done after [$Finished]";
echo
}

getLine(){
tmp=`tail -1 $1`
if [ "$tmp" != "" ];
        then echo "[$tmp]";
        echo "$tmp" >$1;
        else echo "";
fi;
}

spinX $1 $2
To use it, you pass it a process ID and a file that contains the output from that process. As the process continues, a kurby dances on the screen (To let you know that the process has not hanged), and the tail of the output is shown (To let you know what it is doing). When the process ends, the kurby stops dancing and the time it took is displayed.

And here is the file I call "noise":
Code:
#!/bin/bash
while [ i -lt 100 ];do
        i=1
        echo "Look at me count!$"
        sleep 1
        let "i=$i+1"
done
This does nothing but create random output, for testing. It counts from 1 to 99 on the screen.

To run my test, I do the following:

Code:
( noise ) &>tmp.txt & spin $! tmp.txt
It works relatively well, but it is messy. I don't like creating a temp file, and I don't like the messy syntax for calling my program. I decided that I would rather move everything into the spin program, to make using it less messy:

Code:
#Spin Psuedo code
#$1 = command I am about to run
(exec $1) &>tmp.txt & spinX $! tmp.txt
By executing the process inside of the spin code, I can get rid of the tmp file later on without changing a lot of scripts (Or move it, or whatever). I can also call it by passing the command to the script, which I find more elegant.

So here is what I would like to know:

1) If possible, I would love to get rid of the tmp file all together, and store the most recent line of output from script 1 into a variable that script 2 can print out instead... is it possible?
2) How can I run a random command that is passed as an argument? Basic ones work fine, but anything with a pipe fails me.

Example of a script:
Code:
#!/bin/bash
#myEcho.sh
echo;echo "Recieved command: ";echo $1;echo;
echo "Attempting to run command: ";echo
exec $1
Example code for passing commands to script:
Quote:
> myEcho.sh "ls -al" #works
> myEcho.sh 'ls -al' #works

> myEcho.sh "ls -al|grep *.sh" #fail
# Output:
#ls: invalid option -- |
#Try `ls --help' for more information.

> myEcho.sh "ls -al|grep \"*.sh\"" #fail
# Output:
#ls: invalid option -- |
#Try `ls --help' for more information.

> myEcho.sh 'ls -al|grep *.sh\' #fail
# Output:
#ls: invalid option -- |
#Try `ls --help' for more information.
Anyone have ideas?
 
Old 04-21-2010, 02:34 PM   #2
Sergei Steshenko
Senior Member
 
Registered: May 2005
Posts: 4,481

Rep: Reputation: 454Reputation: 454Reputation: 454Reputation: 454Reputation: 454
Quote:
Originally Posted by theaceoffire View Post
...
1) If possible, I would love to get rid of the tmp file all together, and store the most recent line of output from script 1 into a variable that script 2 can print out instead... is it possible?
...
How about the following tiny example:

Code:
sergei@amdam2:~/junk> (stdout_of_command=`echo FOO`; echo stdout_of_command=$stdout_of_command)
stdout_of_command=FOO
sergei@amdam2:~/junk>
- the key item here is a pair of back quotes.
 
Old 04-21-2010, 02:49 PM   #3
Sergei Steshenko
Senior Member
 
Registered: May 2005
Posts: 4,481

Rep: Reputation: 454Reputation: 454Reputation: 454Reputation: 454Reputation: 454
FWIW, your desire not to have temporary files is probably a bad idea.

You assumption apparently is that things work, and my assumption is that (at least, sometimes) they don't. So when things do not work log files of various scripts involved in the process more often than not contain very valuable for postmortem debugging/investigation information.
 
Old 04-21-2010, 09:43 PM   #4
grail
LQ Guru
 
Registered: Sep 2009
Location: Perth
Distribution: Manjaro
Posts: 10,006

Rep: Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191
Or you could try:
Code:
#!/bin/bash
#myEcho.sh
echo;echo "Recieved command: ";echo $1;echo;
echo "Attempting to run command: ";echo
eval $1
 
Old 04-22-2010, 01:21 AM   #5
catkin
LQ 5k Club
 
Registered: Dec 2008
Location: Tamil Nadu, India
Distribution: Debian
Posts: 8,578
Blog Entries: 31

Rep: Reputation: 1208Reputation: 1208Reputation: 1208Reputation: 1208Reputation: 1208Reputation: 1208Reputation: 1208Reputation: 1208Reputation: 1208
How about using the script command to capture the output from the script you have no control over?
Code:
script -c the_script.sh -f <temporary file> -q
Run that in a sub-shell. Now your script can continue, displaying the spinner and grabbing lines of output from the temporary file to display.
 
Old 04-22-2010, 06:48 AM   #6
theaceoffire
LQ Newbie
 
Registered: Apr 2010
Posts: 4

Original Poster
Rep: Reputation: 0
Thanks for the replies

Sergei Steshenko:
Unless I misunderstand your example, I am not sure that work for a script with multiple slow outputs. Is it possible to pipe all output to a script that would continuously replace a variable with the most recent line received?

My current method of &> tmpfile.txt works, but creates a tmpfile, which is slightly annoying.

Also, I am not using the tmpfile as a log, but as a cludge to allow me access to the output of the script without it going to the screen... if I could avoid making random tmp files, it would make me feel better.

Grail
Your script fixes my second, major problem! I can now pass commands like:
Code:
>myEcho "ls -al|grep -E \".*sh\""
And it works! It no longer ignores the pipe!

Thanks!

I don't suppose you guys would know how to pipe a long running script's multiple line value to a variable and access the last line? That would allow me to get rid of my tmp file and (if needed) create a log file..
 
Old 04-22-2010, 08:14 AM   #7
grail
LQ Guru
 
Registered: Sep 2009
Location: Perth
Distribution: Manjaro
Posts: 10,006

Rep: Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191
I am not a 100% on this, but I am sure catkin or others will correct me, but would you not just throw it into a file descriptor,
so something along the lines of:
Code:
exec 6<"file1"
but replace the file being used here with the command you are currently putting into the tmp file.

Like i said, not hunj on this and definitely not tested.
 
Old 04-22-2010, 09:18 AM   #8
theaceoffire
LQ Newbie
 
Registered: Apr 2010
Posts: 4

Original Poster
Rep: Reputation: 0
So for those who wanted to see my final product:

Code:
#!/bin/sh
#progress.sh
tmpFile="/home/me/script/tmp/tmp.txt"    #We store output of passed command.
fail=0                                   #We have not Ctrl+C'ed yet. 
alias wipeRest="tput el;tput cuf 9999"   #Wipe out remaining txt, put cursor far right.
trap theyWantToQuit SIGINT               #If they *do* Ctrl+C, run function 'theyWantToQuit'.

spinX(){
        PROC=$1
        STRT=`date "+%s"`
        while [ -d /proc/$PROC ];do         #While process continues
                tmp=`getLine`;echo -en "\r" "<(''<)   $tmp ";wipeRest;sleep 0.3
                tmp=`getLine`;echo -en "\r" "<(' ')>  $tmp ";wipeRest;sleep 0.3
                tmp=`getLine`;echo -en "\r" " (>'')>  $tmp ";wipeRest;sleep 0.3
                tmp=`getLine`;echo -en "\r" "<(' ')>  $tmp ";wipeRest;sleep 0.3
        done
        END=`date "+%s"`
        Finished=`printf "%02d:%02d:%02d" $((($END-$STRT)/3600)) $((($END-$STRT)/60%60)) $((($END-$STRT)%60))`
        if [ "$fail" == "0" ];then
                echo -en "\r" "(^-^) Done after [$Finished] ";wipeRest;echo
        else    echo -en "\r" "(~.~) Process Canceled after [$Finished]! ";wipeRest;echo
        fi
}

getLine(){
        if [ -f $tmpFile ];then               #We have a tmp file, work with it.
                tmp=`tail -1 $tmpFile`        #Grab the last line.
                echo "[$tmp]"                 #Deliver to user.
                echo "$tmp">$tmpFile          #Replace file with last line.
        else echo ""                          #Got nothing.
        fi
}

theyWantToQuit(){                             #They pressed Ctrl+C, close gracefully. 
        [ -f $tmpFile ]&&rm $tmpFile          #Remove tmp file if it exists.
        kill $PROC >/dev/null 2>&1 & wait     #Don't show stuff on screen.
        fail=1
}

( eval $1 ) &>$tmpFile & spinX $!
^_^ And to use it:

Code:
> progress.sh "{your commands here}" 
> progress.sh "ls -al|grep -E \".*.sh\""
So yeah, it is much easier to use, if you ctrl+c it stops the background process and gets rid of the tmp file while still giving you useful info, and the animation looks smoother since it wipes out the remaining txt on the line. I also moved the cursor *FAR* to the right, so that it won't be constantly moving as the line's width changes.

If anyone can suggest a way of doing this without the tmp file, let me know!
 
Old 04-22-2010, 09:40 AM   #9
Sergei Steshenko
Senior Member
 
Registered: May 2005
Posts: 4,481

Rep: Reputation: 454Reputation: 454Reputation: 454Reputation: 454Reputation: 454
Quote:
Originally Posted by theaceoffire View Post
Sergei Steshenko:
Unless I misunderstand your example, I am not sure that work for a script with multiple slow outputs.
...
So you need a multi-threaded script. Possible, for example, in Perl, don't know about 'bash'.
 
  


Reply

Tags
bash, script, shell



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
[SOLVED] Pass space (or string escaped) as argument to shell script. scmbg Programming 1 10-07-2009 10:15 AM
How to pass commands to asterisk CLI via bash script? Lordmonkey Linux - Newbie 3 03-24-2009 08:59 AM
Howto pass an argument to alias of a script? Goose1 Programming 1 02-17-2008 06:14 PM
How to pass an argument to DHCPCD ? shazam75 Linux - Networking 3 02-27-2005 10:34 AM
PHP pass argument to shell script monzter Programming 2 08-14-2004 06:16 AM

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

All times are GMT -5. The time now is 07:37 AM.

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