LinuxQuestions.org
Welcome to the most active Linux Forum on the web.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Linux Forums > Linux - General
User Name
Password
Linux - General This 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


Reply
  Search this Thread
Old 04-11-2011, 12:17 PM   #1
jtwdyp
Member
 
Registered: Apr 2011
Distribution: antiX, Mageia, OpenSUSE, etc... I multi-boot
Posts: 36

Rep: Reputation: 0
bash: for var in $(cat file): via redirect possible??? NOT a while loop


I multi-boot several Linux distributions with an assortment of additional data partitions. I get frustrated whenever fsck is forced during boot. (It ONLY happens when I'm in a hurry don't you know...) So I wrote a script to automate forced fscking when I do have the time. (And/or while I'm doing something else in another workspace.
Because I multi-boot, I've learned that udev doesn't always assign the same device name to each drive for all distributions. I've had the same partition identified as hda5, sda5, & sdb5 by different distributions (without doing anything to affect the boot order) So my solution is to keep a list of partitions in a specific file on each distro with valid device names according to that distribution's udev process. Actually I'd use LABEL= instead but the labels don't show up in /etc/mtab, and I like to make sure a partition isn't mounted before I try to fsck it.

I can make this work in a for loop using cat. But I've seen so many things about NOT using cat that I wanted to rebuild my script. I can make this work with a redirect instead of cat via a while loop, But I "LIKE" old style for loops. But I can't seem to find a way to make a redirect work with one.

I thought this might make a good first «LinuxQuestions.org» question. I'm also open to any other suggestions on better/alternative methods...

Is it possible to redirect from a file into an actual for loop???

My script is as follows:
Code:
#!/bin/bash
# FsckEm I script to force file system checking on unmounted ext2/ext3/ext4
# partitions in preselected list. FsckEm accepts no options. Partition
# selection is read from the file /root/tmp/FsckEm.txt {which must exist and
# contain one valid partition name per line.

Fcsckit=""
tSt=""
# for Fsckit in $(cat /root/tmp/FsckEm.txt)
while read Fsckit
do
tSt=`grep "${Fsckit}" /etc/mtab`
if [ "$tSt" = "" ] 
then
 	echo "fscking $Fsckit now"
  	e2fsck -f $Fsckit
	echo "done"
else
	echo "«$Fsckit Is mounted»"
	echo "NOT done"
fi
# done 
done < /root/tmp/FsckEm.txt
echo "☻ Fini ☺ "
exit
Thanks
 
Old 04-11-2011, 05:10 PM   #2
bigrigdriver
LQ Addict
 
Registered: Jul 2002
Location: East Centra Illinois, USA
Distribution: Debian stable
Posts: 5,908

Rep: Reputation: 356Reputation: 356Reputation: 356Reputation: 356
You can redirect to a file with > which will overwrite the contents of a file.
You can redirect to a file with >> which will append the contents to a file.
You can redirect from a file with < which will take input from a file.

So, your for loop might work like this: for Fsckit in < /root/tmp/FsckEm.txt
 
Old 04-11-2011, 05:25 PM   #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
Using a redirect is relatively easy except for one thing; for loops do word-breaking when reading the input. The way to work around that is to set your IFS to newline first.
Code:
IFS=$'\n'
for Fsckit in $( </root/tmp/FsckEm.txt )
...
unset IFS
I'd still recommend a while loop instead though as the standard way to handle input-by-line. In addition to not having to muck about with IFS, "$(..)" process substitution branches off a sub-shell.
 
Old 04-11-2011, 06:38 PM   #4
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 think I should clarify a bit more.

Unlike the while+read combination, a for loop can't directly accept input from stdin, which is why a file redirect alone doesn't work (although you can redirect stdout from it to a file). It simply processes a list of "words", either whatever follows "in" on the line, or the "$@" parameters if you don't specify anything.

What's considered a "word" separator is of course determined by your IFS shell variable. This is space+tab+newline by default. So in the above example changing it to newline means spaces and tabs will be ignored, and each "word" will actually be a whole line.

Anyway, to feed the loop you have to first build your word list somehow and insert it where for can read them. In the above I used process substitution. And now that I think about it, here's another way that uses an array instead, along with bash version 4's new mapfile built-in.
Code:
mapfile -t mtarr </etc/mtab

for Fsckit in "${mtarr[@]}" ; do ...
No need to worry about IFS or subshells here, since mapfile works on a per-line basis like read.
 
1 members found this post helpful.
Old 04-12-2011, 12:27 AM   #5
jtwdyp
Member
 
Registered: Apr 2011
Distribution: antiX, Mageia, OpenSUSE, etc... I multi-boot
Posts: 36

Original Poster
Rep: Reputation: 0
Quote:
Originally Posted by David the H. View Post
I think I should clarify a bit more.

Unlike the while+read combination, a for loop can't directly accept input from stdin, which is why a file redirect alone doesn't work
Well That is the short answer. And explains why almost all the examples I've found use the while loop. <sigh> Thanks!
 
Old 04-12-2011, 06:20 AM   #6
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
To be specific, even the while loop isn't reading directly from stdin. It's the read built-in that's doing that. It's just that while evaluates the command you give it during every iteration, whereas for only takes in the next "word" in the list.

http://www.tldp.org/LDP/abs/html/loops1.html
 
  


Reply



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 On
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
how to loop over text file lines within bash script for loop? johnpaulodonnell Linux - Newbie 9 07-28-2015 03:49 PM
bash 2.05b: 'history -s $var' in loop behaves inconsistently mdooligan Linux - General 3 04-02-2010 10:04 PM
trying to redirect text to a file to cat at later point. says file doesn't exist. dr_zayus69 Programming 1 10-02-2005 08:10 AM
bash: /bin/cat: cannot execute binary file inTUXicated Linux - General 9 08-06-2003 07:56 AM

LinuxQuestions.org > Forums > Linux Forums > Linux - General

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