Linux - GeneralThis Linux forum is for general Linux questions and discussion.
If it is Linux Related and doesn't seem to fit in any other forum then this is the place.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
I'm trying to write a shell script which parses the output of the Cyrus IMAP's quota command, which spits out quota usage information for each user. The idea is that if a user is over quota, certain actions will be taken by the script.
The output is space separated (in contrast to commas or tabs). Each row in the output constitutes a user.
Now, I can pull the values (quota usage, user name) I want out of each row with gawk with no problems. The problem I'm having is finding a way to iterate through the output, line-by-line (so that each line is an interation in the loop), and I'd prefer not saving temp files in this process.
I suppose I could write a perl script to do all of this, but given the situation (long story), I'd rather do it with a shell script.
while read FIELD1 FIELD2 FIELD3; do
some stuff based on $FIELD1
some other stuff based on $FIELD2
even more stuff based on $FIELD3
done < /path/to/input/file
May not be exactly what you need, but maybe it'll get you started.
I run this command:
su cyrus -c /usr/lib/cyrus/bin/quota
It spits formatted data like this:
Quota % Used Used Root
102400 0 0 user/john@domain.com
102400 24 333 user/joe@domain.com
262144 84 220504 user/bob@domain.com
102400 104 3 user/jane@domain.com
I want a loop that will give me each row as a string per indice.
i.e. indice 1, the string would contain " 102400 0 0 user/john@domain.com". I can then process this line as needed.
I guess the other part of the question is, how do I get the info into the loop without saving it to a file? Do I do VAR=`cyrus_cmd_above` with the tick marks, and then somehow use that VAR in the loop? Or do I pipe the actual command in somehow?
I need very specific instructions. Help is greatly appreciated.
Or you could do it *much* simpler, as weibullguy already pointed out:
Code:
#!/bin/bash
while read qt pct used addr rest ; do
test "$qt" = "Quota" && continue
# do something with pct and addr here...
done < <(su cyrus -c /usr/lib/cyrus/bin/quota)
is way of directing the output of the quota command into the while loop. I understand the less than directing the data inward.
But what I don't understand (and if you can enlighten me, I would greatly appreciate it) is why there are two arrows and they are separated by spaces. Moreover, why the parenthesis?
I guess I don't see why I can't do this:
done < `su cyrus -c /usr/lib/cyrus/bin/quota`
???
I just want to understand what is happening instead of just blindly following directions.
That, or why can't I pipe su cyrus -c /usr/lib/cyrus/bin/quota to the while loop:
su cyrus -c /usr/lib/cyrus/bin/quota | while x x x x; do
You could do it that way as well. You left out the "read" command after while in your generalized description but I think I caught the meaning.
I will use the other form quite often at the end of cp and mv commands with the -i (interactive option):
< <(yes n)
This will automatically respond "n" to any question.
You can use this form "<( command statements )" to use the output of a command in place of a filename.
I will use this form to do things like sort the input file. For example, the "comm" command can provide common entries or unique entries in two files. It is required that the files be sorted.
So if file1 & file2 are already sorted, then you could use "comm -23 file1 file2" to print out items unique to file1. If they aren't presorted, you could use: "comm -23 <(sort file1) <(sort file2)".
This allows you to use the output of 2 programs as input to the command that expects 2 filenames.
You could use something like "sort file2 | comm -23 file1 -" if only file2 were unsorted, but the < <(command) form allows you to do this with both files. Plus the < <(...) is located at the same place that a file would be in the arguments making it readable once you learn what it is doing.
Do you know of a good web resource that explains in greater detail what you are describing? I'm not sure what keywords to use. (thanks for all the info so far everyone)
For bash, the best is the Advanced Bash Scripting Guide on the www.tldp.org website. ( The pdf file is named "abs-guide.pdf") It consists almost entirely of examples that you can try yourself, which is the best way to learn. Don't let the word "advanced" scare you. The work "Thorough" would be a better description. If there is something that you don't understand in the "info bash" manual, it will probably be explained with examples in the "abs-guide.pdf". Not having enough examples is the problem I have with a lot of documentation. After covering command substitution, there are 15 links to other scripts in the Guide.
One of the first chapters deals with special characters. You can look there to find out what && does, or <<.
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.