Hello, On Thu, 24 May 2012, David C. Rankin wrote:
On 05/24/2012 05:57 AM, David Haller wrote:
And stdin 'is empty', calc has read all lines, read x doesn't see any more lines:
So basically in z=$(calc -p '21+21') calc sees:
$ calc -p '21+21' \ bar 3 \ bar 4 \ bar 5 \ bar 6 \ bar 7 \ bar 8
and discards everything else in the line beginning with the first 'bar' because as far as calc knows that is some undefined text?
I'd have to look into the source how calc handles arguments vs. stdin, but ...
But then just continues reading the rest of the 'bar #' until it runs out of things to read?
... it seems to eval first the arguments, then read stdin (at least 4KB of it), tries to eval that and in this case, barfs on the first 'bar'[0].
$ printf "bar %s\n" $(seq 8) | while read x; read y; do \ z=$(strace -s 40 -eread calc -p '21+21'); echo "x=$x; y=$y; z=$z"; \ done [more reads of ELF binaries snipped and pruned] read(3, "\177ELF..., 832) = 832 read(0, "bar 3\nbar 4\nbar 5\nbar 6\nbar 7\nbar 8\n", 4096) = 36 "bar" is undefined
x=bar 1; y=bar 2; z=42
As you can see in the last 'read', calc read 'fd 0', i.e. stdin upto and_including_ the last line containing 'bar 8\n'. Tries to parse that stuff and barfs on the 'bar 3' on line 3 ('read x' and 'read y' read lines 1 and 2, as you can see in the 'echo' output).
Aah.. Gotcha :)
*bg*
The part inside the '{ }' replaces your script!
$ printf "bar %s\n" $(seq 4) | { \ IFS=$'\n'; \ for x in $(seq 10 14); do \ z=$(calc -p "$x+1"); \ echo "x=$x; z=$z"; \ done; } "bar" is undefined
x=10; z=11 x=11; z=12 x=12; z=13 x=13; z=14 x=14; z=15
But: the for-loop doesn't abort once calc has read stdin (i.e. the 'printf 'bar %s\n' $(seq 4)' output), as the for loop does not depend on stdin.
OK, if I'm learning anything here, then that looks like:
$ bar 1 \ bar 2 \ bar 3 \ bar 4 | { ..stuff.. z=$(calc -p "$x+1") ..stuff.. }
calc still chokes on 'bar 1', but it has already executed the for x in $(seq 10 14) before it dies. So the calculations finished in the '{}'s before calc ate: 'bar 1 \n bar 2 \n bar 3 \n bar 4'
Almost. You for got: calc is called from inside the for-loop. That means: for x = 10 calc -p 10+1 ### evals and prints 10+1; gobbles stdin ### ("bar 1" till "bar 4"), barfs on the first ### 'bar' and exits[0] for x = 11 calc -p 11+1 ### evals and prints 11+1, stdin is empty for x = 12 calc -p 12+1 ### evals and prints 12+1, stdin is empty ...
#!/bin/bash exec</dev/null ^^^^^^^^^^^^^^^^ IFS=$'\n' for l in $(<gtkrc-file.txt); do ....
Compare:
$ printf "bar %s\n" $(seq 4) | { exec</dev/null; IFS=$'\n'; \ for x in $(seq 10 14); do \ z=$(calc -p "$x+1"); echo "x=$x; z=$z"; done; } x=10; z=11 x=11; z=12 x=12; z=13 x=13; z=14 x=14; z=15
That way, you redirect your script's stdin from /dev/null, and thus 'calc' can't read anything from there that might confuse it.
That is the 'nugget' to be found. I would not have seen that or recognized that as an option for eons. That's where the (knowledge, skill, training, years of experience, etc..) really makes the difference. I completely lacked the appreciation for that level of redirection understanding. Oh, I've dug fairly far into redirection of stdin, stdout, and stderr, but stumbled face-first into what calc was doing with it ;-)
Yeah, that redirecting with 'exec' (usually at the top of a script) is a topic easily overlooked. Have a look into a configure script (search for 'exec' and after that look at a couple of how those redirections are used later on (search for '>&')). Homework: show me at least 2 more versions to redirect besides the 2 already mentioned ;P
HTH, and ask if you're still (or again) confused,
dnh -- It does! That was excellent, and the archives will hold onto this thread to help close the gap for many to come in the levels of redirection understanding (as well as provide a jumping off point for furthering debugging skills)
Thanks a lot.
This is something that probably needs to be forwarded to the ABS folks for inclusion in the section of redirection or as it's own separate 'Advanced Topics in Redirection - Understanding Potential Errors'.
Good idea. I.e. how programs reading stdin (or something else, e.g. fd 3 which is used in configure scripts) can have "weird" effects inside a contstruct reading stdin too.
What was it -- I believe attributed to Einstein -- "True Genius is the ability to explain the complexities of nature to a child." Thanks!
*blush* Well, if you and hopefully some others reading along have learned two things, I'm a happy bunny: 1. any[1] error message ends up in a call to the syscall write(2), and any process created ends up in a call to a exec* syscall, which is why usually the 'process' filter is more verbose but possibly better than the specific 'execve' filter when using strace. Anyway: if you get an error and can't tell from program it actually is, do NOT be afraid to grab the big hammer: strace [-o output.strace] [-s 128] -f \ -e write,process $PROGRAM $ARGS and then dig through the output looking for a 'write(FD, ...)' (FD being 1 or 2) with your error message (thus getting the PID and thus being able to find the process by looking for a fork/clone/exec* call with that PID) [2]. 2. in bash: all programs in a script, and all programs inside a block with a redirection of FDs (e.g. stdin, stdout, stderr) *SHARE that redirection* unless they are called with explicit redirections themselves. E.g. in a $ printf "10+%s\n" 1 2 3 | { read x; echo "x=$x"; calc -p "20+$x"; read y; echo "y=$y"; } x=10+1 31 ### this is calc's eval'ed "20+$x" as an argument 12 ### this is calc's "10+2" from stdin 13 ### this is calc's "10+3" from stdin y= or $ printf "10+%s\n" 1 2 | { read x; echo "x=$x"; cat; read y; echo "y=$y"; } x=10+1 10+2 y= both reads and calc (and cat) share the redirection of stdin (to the stdout of the 'printf'), as in the while-loop discussed upthread. Short version: std{in,out,err} (and other filedescriptors) is std{in,out,err} unless redirected, and redirection is hereditary! Maybe that last sub-sentence would be a good point to include in the (official) docs (man bash, ABS) more explicitly. HTH, again, -dnh, definitely not a genius [0] I love it when metasyntactic variables and descriptions make such "sense" ;) [1] not 100% sure about (remote) e.g. syslog-messages [2] maybe we should hold a little seminar "basic use and interpreting the output of strace and ltrace" on the opensuse-programming list (which is pretty quiet). -- Nutzerdaten verhalten sich wie ideale Gase. Sie nehmen jedes verfügbare Volume(n) sofort vollständig ein. -- Mantra eines Uni-Admins [Userdata behave like ideal gases. They immediately take up all available volume(s). -- Mantra of a university admin] -- To unsubscribe, e-mail: opensuse+unsubscribe@opensuse.org To contact the owner, e-mail: opensuse+owner@opensuse.org