rudolf@oce.orst.edu (Jim Rudolf) (04/24/89)
If I have a Bourne script called 'foo' and I call it with the arguments: foo "color = red" "size = big" then from within foo they will be read as: $1 = "color = red" $2 = "size = big" However, I want to read from stdin (or maybe a redirected pipe), and I can't get it to work no matter what strange combination of quotes I use! I would like to do something like: read args for i in $args . . so I can process each string in turn. Why can't I get this to work? Do command line arguments get treated differently than arguments read from within the script? Any suggestions would be greatly appreciated. Thanks, Jim Rudolf ---------------------------------------------------------------------------- Internet: rudolf@oce.orst.edu "All opinions herein are mine" UUCP: {tektronix,hp-pcd}!orstcs!oce.orst.edu!rudolf ----------------------------------------------------------------------------
logan@vsedev.VSE.COM (James Logan III) (04/25/89)
In article <10166@orstcs.CS.ORST.EDU> rudolf@oce.orst.edu (Jim Rudolf) writes:
# If I have a Bourne script called 'foo' and I call it with the arguments:
# foo "color = red" "size = big"
# then from within foo they will be read as:
# $1 = "color = red"
# $2 = "size = big"
# However, I want to read from stdin (or maybe a redirected pipe), and I
# can't get it to work no matter what strange combination of quotes I use!
# I would like to do something like:
# read args
# for i in $args
# .
# .
# so I can process each string in turn.
If I have interpreted your question correctly, you want to read
the lines
color = red
size = big
into your script and have each line read into a variable.
To do this, use the construct:
while read DEFINITION; do
echo "$DEFINITION";
.
.
.
done;
BTW, you can also read from a specific file by redirecting the
input to the read command like this:
INPUTFILE="some_file";
while read DEFINITION <$INPUTFILE; do
echo "$DEFINITION";
.
.
.
done;
-Jim
--
Jim Logan logan@vsedev.vse.com
VSE Software Development Lab uucp: ..!uunet!vsedev!logan
(703) 329-4654 inet: logan%vsedev.vse.com@uunet.uu.net
dce@Solbourne.COM (David Elliott) (04/25/89)
In article <1493@vsedev.VSE.COM> logan@vsedev.VSE.COM (James Logan III) writes: >BTW, you can also read from a specific file by redirecting the >input to the read command like this: > > INPUTFILE="some_file"; > > while read DEFINITION <$INPUTFILE; do > echo "$DEFINITION"; > . > . > . > done; Watch out for this one. It's very important to note that in the "standard" shells (those that come with most commercial UNIXes), the redirection causes a subshell to be spawned to run the loop. The result is that any variables set inside the loop will not have the same values when the loop is exited. So, if the input data are used to set variables to be used later in the program, this won't work. A typical trick is exec 3<&0 0<"$INPUTFILE" while read DEFINITION do echo "$DEFINITION" done exec 0<&3 The first exec makes fd 3 a duplicate of fd 0 (stdin), and redirects stdin. The second exec changes fd 0 back to what it was. -- David Elliott dce@Solbourne.COM ...!{boulder,nbires,sun}!stan!dce
mchinni@pica.army.mil (Michael J. Chinni, SMCAR-CCS-E) (04/26/89)
Jim Rudolf <rudolf@oce.orst.edu> writes: > If I have a Bourne script called 'foo' and I call it with the arguments: > foo "color = red" "size = big" > then from within foo they will be read as: > $1 = "color = red" > $2 = "size = big" > However, I want to read from stdin (or maybe a redirected pipe), and I > can't get it to work no matter what strange combination of quotes I use! > I would like to do something like: > read args > for i in $args > . > . > so I can process each string in turn. Why can't I get this to work? > Do command line arguments get treated differently than arguments read > from within the script? Any suggestions would be greatly appreciated. As to how to do this, others have given answers. As to why this doesn't work, read on. The problem is with the "for" loop. The "for" construct uses a list of arguments which are words separated by tabs/spaces. Therefore, "for" will split your arguments into their individual words. Given your command line arguments: echo $1 echo $2 will produce color = red size = big I know of no way to do what you want using a "for" loop. /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ Michael J. Chinni Chief Scientist, Simulation Techniques and Workplace Automation Team US Army Armament Research, Development, and Engineering Center User to skeleton sitting at cobweb () Picatinny Arsenal, New Jersey and dust covered terminal and desk () ARPA: mchinni@pica.army.mil "System been down long?" () UUCP: ...!uunet!pica.army.mil!mchinni /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
friedl@vsi.COM (Stephen J. Friedl) (04/26/89)
In article <1493@vsedev.VSE.COM>, logan@vsedev.VSE.COM (James Logan III) writes: > > BTW, you can also read from a specific file by redirecting the > input to the read command like this: > > while read DEFINITION < inputfile; do > echo "$DEFINITION"; > # other stuff > done; This is a common mistake. The redirection applies to only the read command, and every time the while hits the read, the input file is opened anew and the same first line is read over and over (and the while never terminates). Try: while read line < /etc/passwd ; do echo $line done and you'll learn your encrypted root password quite well. The {Bou,Ko}rn shells support piping and redirection into and out of control flow, so things like: while read foo ; do stuff here done < inputfile or while condition ; do stuff here done > outputfile or grep stuff file | while read line ; do .... ; done all do things that make sense. Steve -- Stephen J. Friedl / V-Systems, Inc. / Santa Ana, CA / +1 714 545 6442 3B2-kind-of-guy / friedl@vsi.com / {attmail, uunet, etc}!vsi!friedl As long as Bush is in office, you'll never see Nancy Reagan in *my* .sig.
rikki@macom1.UUCP (R. L. Welsh) (04/27/89)
From article <19311@adm.BRL.MIL>, by mchinni@pica.army.mil (Michael J. Chinni, SMCAR-CCS-E): > Jim Rudolf <rudolf@oce.orst.edu> writes: >> If I have a Bourne script called 'foo' and I call it with the arguments: >> foo "color = red" "size = big" >> then from within foo they will be read as: >> $1 = "color = red" >> $2 = "size = big" >> However, I want to read from stdin (or maybe a redirected pipe), and I >> can't get it to work no matter what strange combination of quotes I use! >> I would like to do something like: >> read args >> for i in $args >> . >> . >> so I can process each string in turn. Why can't I get this to work? Try: \"x = value\" This worked for me -- you need to get the " passed to the for line. From vn Thu Apr 27 10:12:11 1989 Subject: Re: I Live Newsgroups: dfw.test References: <4498@psuvax1.cs.psu.edu> From article <4498@psuvax1.cs.psu.edu>, by Elvis@cup.portal.com (The King): > Just testing. > Elvis Hi Elvis. From vn Thu Apr 27 10:13:21 1989 Subject: Re: test Newsgroups: dc.test References: <12610@jhunix> Distribution: dc From article <12610@jhunix>, by tester@jhunix (tester): > testing Testing followup. -- - Rikki (UUCP: grebyn!macom1!rikki)
rikki@macom1.UUCP (R. L. Welsh) (04/27/89)
> Jim Rudolf <rudolf@oce.orst.edu> writes: ... >> However, I want to read from stdin (or maybe a redirected pipe), and I >> can't get it to work no matter what strange combination of quotes I use! >> I would like to do something like: >> read args >> for i in $args Try: \"x = value\" This worked for me -- you need to get the " passed to the for line. -- - Rikki (UUCP: grebyn!macom1!rikki)
stever@tree.UUCP (Steve Rudek) (04/28/89)
In article <870@marvin.Solbourne.COM>, dce@Solbourne.COM (David Elliott) writes: > exec 3<&0 0<"$INPUTFILE" > while read DEFINITION > do > echo "$DEFINITION" > done > exec 0<&3 > > The first exec makes fd 3 a duplicate of fd 0 (stdin), and > redirects stdin. The second exec changes fd 0 back to what > it was. I've never seen anything quite like this. It is beautiful, exciting and rather bizarre; shell at its best! :-) I can guess that you're creating a file descriptor 3 *strictly* to preserve the (address??) of stdin. But the 0<"$INPUTFILE" bit boggles my mind. How is this different from just <$INPUTFILE I guess the leading "exec" is important in understanding this? Could you explain? By the way, how would: while read DEFINITION <$INPUTFILE do done differ from: while read DEFINITION do done <$INPUTFILE Or wouldn't it? If not too much trouble, I'd appreciate a *copy* of any responses via email since I really have a considerable interest in the answer and fear I might otherwise miss a newsgroup response. ---------- Steve Rudek {ucbvax!ucdavis!csusac OR ames!pacbell!sactoh0} !tree!stever
logan@vsedev.VSE.COM (James Logan III) (04/28/89)
In article <1493@vsedev.VSE.COM> I wrote:
# BTW, you can also read from a specific file by redirecting the
# input to the read command like this:
#
# INPUTFILE="some_file";
#
# while read DEFINITION <$INPUTFILE; do
# echo "$DEFINITION";
# .
# .
# .
# done;
Oooops, I screwed up! What I wrote above will read the first line
again and again! The best solution is:
INPUTFILE="some_file";
exec 4<$INPUTFILE;
while read DEFINITION 0<&4; do
echo "$DEFINITION";
.
.
.
done;
exec 4<&-;
since the alternative construct:
INPUTFILE="some_file";
while read DEFINITION; do
echo "$DEFINITION";
.
.
.
done <$INPUTFILE;
has the side-effect of redirecting the input of every command
invoked from within the while loop.
-Jim
--
Jim Logan logan@vsedev.vse.com
VSE Software Development Lab uucp: ..!uunet!vsedev!logan
(703) 329-4654 inet: logan%vsedev.vse.com@uunet.uu.net
logan@vsedev.VSE.COM (James Logan III) (04/28/89)
In article <870@marvin.Solbourne.COM> dce@Solbourne.com (David Elliott) writes: # In article <1493@vsedev.VSE.COM> logan@vsedev.VSE.COM (James Logan III) writes: # >BTW, you can also read from a specific file by redirecting the # >input to the read command like this: # > # > INPUTFILE="some_file"; # > # > while read DEFINITION <$INPUTFILE; do # > echo "$DEFINITION"; # > . # > . # > . # > done; This construct has a BIG problem. I corrected it in a previous posting. # # A typical trick is # # exec 3<&0 0<"$INPUTFILE" # while read DEFINITION # do # echo "$DEFINITION" # done # exec 0<&3 # # The first exec makes fd 3 a duplicate of fd 0 (stdin), and # redirects stdin. The second exec changes fd 0 back to what # it was. This has the side effect of redirecting stdin for every command invoked inside the while loop. (Take a look at my corrected posting.) Besides, it has the same effect as the simpler construct: while read DEFINITION; do echo "$DEFINITION"; done <$INPUTFILE; Under System V (on 3B2, Altos, and XENIX at least) the variable "DEFINITION" is not set in a sub-shell. To do this you would have to do something silly like: while `read DEFINITION`; do echo "$DEFINITION"; done; Perhaps this isn't the case in BSD UNIX. -Jim -- Jim Logan logan@vsedev.vse.com VSE Software Development Lab uucp: ..!uunet!vsedev!logan (703) 329-4654 inet: logan%vsedev.vse.com@uunet.uu.net
ka@june.cs.washington.edu (Kenneth Almquist) (04/30/89)
rudolf@oce.orst.edu (Jim Rudolf) writes: > If I have a Bourne script called 'foo' and I call it with the arguments: > foo "color = red" "size = big" > then from within foo they will be read as: > $1 = "color = red" > $2 = "size = big" > However, I want to read from stdin (or maybe a redirected pipe), and I > can't get it to work no matter what strange combination of quotes I use! > I would like to do something like: > read args > for i in $args > . > . > so I can process each string in turn. Why can't I get this to work? > Do command line arguments get treated differently than arguments read > from within the script? Any suggestions would be greatly appreciated. Presumably you want to read in a single line with multiple quoted strings in it. The read command doesn't handle quoted strings. (The shell manual page lies.) One possible solution is to use the eval command: read line || exit 0 # exit if end of file eval "set $line" # parse line for i in "$@" ... Let's work through an example. Assume that the input line is "color = red" "size = big" Then the read command will store the line in the variable "line". The second command will run the eval command with a single argument, the string set "color = red" "size = big" The set command assigns its arguments to the positional parameters, so you will get $1 = "color = red" $2 = "size = big" The for loop will then step through the positional parameters. Several warnings about this. First, if the first argument to set begins with a minus or plus sign, it will be interpreted as an option. Second, this won't work if the number of arguments to set is zero. Third, the set command changes the positional parameters, making the original arguments to the shell procedure inaccessible. And fourth, if the argument to "set" is not syntactically correct, the shell procedure will terminate. Kenneth Almquist
davidsen@steinmetz.ge.com (Wm. E. Davidsen Jr) (05/03/89)
In article <275@tree.UUCP> stever@tree.UUCP (Steve Rudek) writes: | By the way, how would: | while read DEFINITION <$INPUTFILE | do | done | | differ from: | while read DEFINITION | do | done <$INPUTFILE | | Or wouldn't it? Redirection on the read command would open and read the INPUTFILE every time throught the loop (ie. read 1st line forever). On the done line the redirect causes all commands in the loop to read their stdin from INPUTFILE. If you want to read successive lines from a file and process them, but not redirect stdin, here's a technique (I invented it myself, but I doubt that it's unique). while read name 0<&3 do : whatever here : stdin is still tty done 3< $INPUTFILE This works with SysV sh as well as ksh (I didn't try BSD, sorry). -- bill davidsen (wedu@crd.GE.COM) {uunet | philabs}!steinmetz!crdos1!davidsen "Stupidity, like virtue, is its own reward" -me