LinuxQuestions.org
Visit Jeremy's Blog.
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 03-05-2009, 09:02 AM   #1
eldorel
LQ Newbie
 
Registered: Mar 2009
Posts: 3

Rep: Reputation: 0
Post pipe as Bash function input


I maintain a system that deals with hundreds of text files at a time and find myself using infinite loops at the command line fairly frequently for doing things like monitoring a directory for a change, or check the number of files in a location every 5 seconds.

Usually this entails using something similar to

Code:
  while [ 1 ]; do clear; date; ls -al stuff/ | grep -v drwx | cut -d " " -f 6-  ; sleep 5; done
OR

Code:
  while [ 1 ]; do clear; date; ls -al stuff/ | wc -l; sleep 5; done
Since the majority of this is always the same, I decided to write a short function to handle the looping portion.

Code:
loop ()
{
        while [ 1 ]; do 
                clear 
                date
                echo `$@`
                sleep 1
         done
}
This works fine when executed as long as there are no pipes in the input command to be looped.

For example:

This works
Code:
loop ls -al stuff/
This doesn't
Code:
loop "ls -al stuff/ | wc -l"
The problem appears to be that the pipe is treated as only a character, even when wrapped in backticks.

Hopefully someone can just tell me there's an easier way to do this.

Thanks in advance,
eldorel

Last edited by eldorel; 03-05-2009 at 10:42 AM. Reason: forgot to add quotes
 
Old 03-05-2009, 10:15 AM   #2
ta0kira
Senior Member
 
Registered: Sep 2004
Distribution: FreeBSD 9.1, Kubuntu 12.10
Posts: 3,078

Rep: Reputation: Disabled
Try using eval $@ instead of echo `$@`.
ta0kira
 
Old 03-05-2009, 10:19 AM   #3
Hko
Senior Member
 
Registered: Aug 2002
Location: Groningen, The Netherlands
Distribution: Debian
Posts: 2,536

Rep: Reputation: 111Reputation: 111
Just use the "watch" program. It is more flexible, made and tested especially to do this kind of things (see: man watch).

It comes as part of the procps package together with stuff like "top" and "vmstat", so I suppose all but the most stripped down distro's wil have it installed by default.

To do your thing with "watch":
Code:
watch "ls -al /tmp | wc -l"
 
Old 03-05-2009, 10:25 AM   #4
colucix
LQ Guru
 
Registered: Sep 2003
Location: Bologna
Distribution: CentOS 6.5 OpenSuSE 12.3
Posts: 10,509

Rep: Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983Reputation: 1983
The problem is that when you run simply
Code:
loop ls -al stuff/ | wc -l
the pipe is not passed as argument to the function but it is resolved in the parent shell. This means the command at right hand side of the pipe waits for the completion of the input before giving the result. Since you have an infinite loop in the function, the wc -l command waits forever without being executed.

However, if you have a command capable of taking buffered input on the right hand side of the pipe, it works. An example is grep
Code:
loop ls -al stuff/ | grep -v drwx
If you want to monitor the number of files continuously, you have to pass a literal pipe as argument by protecting it from the shell using quotes, as you already noticed. The problem now is the way you run that string as a command inside the function. First of all you don't really need echo, nor back ticks. Instead it has the side effect of displaying the output in a single line. If you want to run a command which is stored in a variable or in the arguments of the script, just do
Code:
$var
or
Code:
$@
respectively. Moreover if you have some special characters (like a pipe) that needs to be evaluated by the shell and not interpreted literally, just use eval. In conclusion - to work with pipes, the way you expect - your function should be
Code:
loop ()
{
        while true
        do 
          clear 
          date
          eval $@
          sleep 1
        done
}
Edit: Beaten by the more concise post by ta0kira!
Hko, good advice! I always forget the watch command.

Last edited by colucix; 03-05-2009 at 10:29 AM.
 
Old 03-05-2009, 10:38 AM   #5
eldorel
LQ Newbie
 
Registered: Mar 2009
Posts: 3

Original Poster
Rep: Reputation: 0
Thank you

Eval... Duh.

See, I knew you guys would be able to pinpoint my mistake. Guess that's what I get for trying to fix a problem before I get my coffee, Thanks.

As for reinventing the wheel, watch is exactly what I was looking for.

Thanks for all of your help guys..

eldorel
 
  


Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

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
Shell script pipe input - bash mostly laikos Programming 4 11-09-2008 05:14 PM
Bash Scripting: Pipe input to script vs. $1 jhwilliams Linux - Software 3 12-21-2007 10:54 PM
Can't get user input when using a pipe to my C++ program ta0kira Programming 18 04-22-2006 12:53 PM
my mouse input is takes as keyboard input in BASH e1000 Slackware 5 12-08-2003 03:00 PM
read and pipe function dummyagain Programming 13 09-24-2003 10:36 PM

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

All times are GMT -5. The time now is 09:11 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