Re: Should this be this way?
On 02/26/2013 02:03 AM, Linda Walsh wrote: My login shell is /bin/bash (i.e. not /bin/sh); SHELL=/bin/bash as well. Typing 'which bash' gives /bin/bash, and whence bash: bash is /bin/bash. which is not always correct. Use type builtin. I had the foll0wing script which acts differently based on whether or not it has a #!/bin/bash at the top: (i.e., as it is displayed below, it fails; one need remove the [] from the first line for it to work. #[!/bin/bash] I think the line above will produce unspecified behavior. while read fn;do base=${fn%.*} if [[ -e $base ]]; then if [[ $base -ot $fn ]]; then echo "compressed version ($fn) seems newer" elif [[ $base -nt $fn ]]; then echo "uncompressed version ($base) seem newer" else echo "both versions ($base) are same age" fi else echo "No uncompressed version of $base exists" fi done < <(find . -type f -name \*.[0-9].\*[zZ]\* ) - The error: ./manscan.sh: line 12: syntax error near unexpected token `<' ./manscan.sh: line 12: `done < <(find . -type f -name \*.[0-9].\*[zZ]\* )' Why would this script behave differently if the first line exists or not? (Putting the !shell in square brackets, made it a comment, not an interpreter spec, thus the same effect as if it wasn't there ('cept the line number of the error is 1 less if you don't have the line! ;-)). So...is this correct behavior for some[inane POSIX] reason? Seems a bit odd to me. Is kernel or bash processing the shebang? RR
Re: Should this be this way?
On Tue, Feb 26, 2013 at 11:22 AM, Roman Rakus wrote: > On 02/26/2013 02:03 AM, Linda Walsh wrote: >> >> My login shell is /bin/bash (i.e. not /bin/sh); SHELL=/bin/bash as well. >> Typing 'which bash' gives /bin/bash, and whence bash: bash is /bin/bash. > > which is not always correct. Use type builtin. > >> >> I had the foll0wing script which acts differently based on >> whether or not it has a #!/bin/bash at the top: (i.e., as it is >> displayed below, it fails; one need remove the [] from the first >> line for it to work. >> >> #[!/bin/bash] > > I think the line above will produce unspecified behavior. I think the kernel will try to find a shebang and not recognize it, then the current shell will try to run it Man bash says: If this execution fails because the file is not in executable format, and the file is not a directory, it is assumed to be a shell script, a file containing shell commands. A subshell is spawned to execute it. This subshell reinitializes itself, so that the effect is as if a new shell had been invoked to handle the script, with the exception that the locations of commands remembered by the parent (see hash below under SHELL BUILTIN COMMANDS) are retained by the child. SUS says If the execve() function fails due to an error equivalent to the [ENOEXEC] error defined in the System Interfaces volume of POSIX.1-2008, the shell shall execute a command equivalent to having a shell invoked with the pathname resulting from the search as its first operand, with any remaining arguments passed to the new shell, except that the value of "$0" in the new shell may be set to the command name. If the executable file is not a text file, the shell may bypass this command execution. In this case, it shall write an error message, and shall return an exit status of 126.
Re: Should this be this way?
On 2/26/13 12:41 AM, Linda Walsh wrote: > It isn't using the current value of SHELL as my shell nor the value > of my login shell. It uses $0 (or, rather, the basename of $0), which is initialized from the parent shell's argv[0]. What is $0 set to? > > It is forcing interpretation into /bin/sh, which I don't use. Not quite. It is enabling posix mode. There are a couple of ways to do that: $POSIXLY_CORRECT, $0 == "sh", or set -o posix. Chet -- ``The lyf so short, the craft so long to lerne.'' - Chaucer ``Ars longa, vita brevis'' - Hippocrates Chet Ramey, ITS, CWRUc...@case.eduhttp://cnswww.cns.cwru.edu/~chet/
Re: Should this be this way?
Chet Ramey wrote: > On 2/26/13 12:41 AM, Linda Walsh wrote: > >> It isn't using the current value of SHELL as my shell nor the value >> of my login shell. > > It uses $0 (or, rather, the basename of $0), which is initialized from > the parent shell's argv[0]. What is $0 set to? "-bash" > >> It is forcing interpretation into /bin/sh, which I don't use. > > Not quite. It is enabling posix mode. There are a couple of ways to > do that: $POSIXLY_CORRECT, $0 == "sh", or set -o posix. --- Not doing either of those here... I do have "MAN_POSIXLY_CORRECT" so man only gives me 1 man page followed by the section numbers of other man pages, as opposed to acting like 'less' with multiple files (i.e. next to go to next page)... But I don't see anything that would suggest to to bash to flip into shell. The code that the original poster pointed me at doesn't appear to have a check for what shell it was invoked as (or what is in $0). It seems to go off the fact that line 0 didn't have an interpreter line specified... I.e., what I see is: #next line is #5033 /* Is this supposed to be an executable script? If so, the format of the line is "#! interpreter [argument]". A single argument is allowed. The BSD kernel restricts the length of the entire line to 32 characters (32 bytes being the size of the BSD exec header), but we allow 80 characters. */ if (sample_len > 0) { #if !defined (HAVE_HASH_BANG_EXEC) if (sample_len > 2 && sample[0] == '#' && sample[1] == '!') return (execute_shell_script (sample, sample_len, command, args, env)); else #endif if (check_binary_file (sample, sample_len)) { internal_error (_("%s: cannot execute binary file"), command); return (EX_BINARY_FILE); } } /* We have committed to attempting to execute the contents of this file as shell commands. */ #if 1 <---Note problem?? (SuSE ism?) larray = strvec_len(args) + 1; args = strvec_resize(args, larray + 1); for (i = larray - 1; i; i--) args[i] = args[i - 1]; args[0] = savestring(_PATH_BSHELL); args[1] = command; args[larray] = (char *)0; SETOSTYPE (0);/* Some systems use for USG/POSIX semantics */ execve ("/bin/sh", args, env); SETOSTYPE (1); internal_error (_("%s: cannot execute: %s"), command, strerror (errno)); #else initialize_subshell (); set_sigint_handler (); /* Insert the name of this shell into the argument list. */ larray = strvec_len (args) + 1; args = strvec_resize (args, larray + 1); for (i = larray - 1; i; i--) args[i] = args[i - 1]; args[0] = shell_name; args[1] = command; args[larray] = (char *)NULL; if (args[0][0] == '-') args[0]++; #if defined (RESTRICTED_SHELL) if (restricted) change_flag ('r', FLAG_OFF); #endif if (subshell_argv) { /* Can't free subshell_argv[0]; that is shell_name. */ for (i = 1; i < subshell_argc; i++) free (subshell_argv[i]); free (subshell_argv); } dispose_command (currently_executing_command);/* XXX */ currently_executing_command = (COMMAND *)NULL; subshell_argc = larray; subshell_argv = args; subshell_envp = env; unbind_args (); /* remove the positional parameters */ longjmp (subshell_top_level, 1); /*NOTREACHED*/ #endif return (EX_NOEXEC); }
Re: Should this be this way?
POSIX specifies the behavior of a shell. This tells Chet how he has to make Bash behave (with some leeway). There are all kinds of silly little details and ambiguities that Chet has to worry about. However, YOU as a shell script writer do not have to worry about all that crap. All you have to do is put the proper shebang line in your script, and then -- like magic! -- your script will be executed using the interpreter you specified. End of problem.
Re: Should this be this way?
Greg Wooledge wrote: > POSIX specifies the behavior of a shell. This tells Chet how he has to > make Bash behave (with some leeway). There are all kinds of silly little > details and ambiguities that Chet has to worry about. > > However, YOU as a shell script writer do not have to worry about all > that crap. All you have to do is put the proper shebang line in your > script, and then -- like magic! -- your script will be executed using > the interpreter you specified. --- Except it isn't a script -- it's input that came from the terminal, that got repetitively edited using vi mode, until it got saved in a file so it could continue to be edited, and stay on the screen while executing it in the original window. I.e. it's the natural evolution of input you type into the terminal. How often, when at a terminal, do you type #!/bin/bash before every line? To have your script suddenly change behavior because you saved it in a file and executed it by name would probably surprise most people.
Re: Should this be this way?
On Tue, Feb 26, 2013 at 01:27:35PM -0800, Linda Walsh wrote: > Except it isn't a script -- it's input that came from > the terminal, that got repetitively edited using vi mode, until it got > saved in a file so it could continue to be edited, and stay on the screen > while executing it in the original window. If it's in a file, it is a script. Do note that commands in a file are not equivalent to commands typed into an interactive shell. If the commands set variables or change directory or toggle shell options, those changes won't persist because you're running a script, and they go away when the script terminates. Maybe you want a shell function instead. > How often, when at a terminal, do you type #!/bin/bash before every line? When I've put the contents into a file? Every. single. time.
Re: Should this be this way?
On 2/26/13 3:39 PM, Linda Walsh wrote: > > > Chet Ramey wrote: >> On 2/26/13 12:41 AM, Linda Walsh wrote: >> >>> It isn't using the current value of SHELL as my shell nor the value >>> of my login shell. None of this is relevant, see below. > #if 1 <---Note problem?? Your vendor, which may be SuSE, has changed bash and shipped the modified version. They have chosen to interpret Posix ("a command equivalent to having a shell invoked with the pathname resulting from the search as its first operand") as requiring that bash actually invoke /bin/sh, with all of the consequences of starting a fresh process. I imagine they didn't change the man page while they were at it, nor produce a list somewhere of the changes they made. I'm always going to answer from the perspective of bash as I distribute it. This is a different case. You should follow Greg's excellent advice and include the #! line. That's the only way you can be sure of what you get. > (SuSE ism?) > larray = strvec_len(args) + 1; > args = strvec_resize(args, larray + 1); > > for (i = larray - 1; i; i--) > args[i] = args[i - 1]; > > args[0] = savestring(_PATH_BSHELL); > args[1] = command; > args[larray] = (char *)0; > > SETOSTYPE (0); /* Some systems use for USG/POSIX semantics */ > execve ("/bin/sh", args, env); > SETOSTYPE (1); > > internal_error (_("%s: cannot execute: %s"), command, strerror (errno)); Chet -- ``The lyf so short, the craft so long to lerne.'' - Chaucer ``Ars longa, vita brevis'' - Hippocrates Chet Ramey, ITS, CWRUc...@case.eduhttp://cnswww.cns.cwru.edu/~chet/
Re: More fun with IFS
On Sunday, February 24, 2013 10:26:52 PM Thorsten Glaser wrote: > Dan Douglas dixit: > > >Zsh and pdkshes produce: > > > >one:::two:three:::four > > > >For all of the above, which I think is wrong for the last 4. ksh93 > >produces: > > Why is it incorrect? This test was intended to demonstrate expansions within assignment contexts. ''one:::two'' and ''three:::four'' are separate arguments to begin with. Word splitting and pathname expansion shouldn't occur within (ordinary) assignment contexts. I think the mksh (and zsh) results are wrong because I can't think of any reason it should be inserting a '':'' between the two arguments, especially for the ''$@'' variants, either quoted or unquoted. It certainly can't be because of a word splitting step. It's already been pointed out that different shells interpret unquoted @ and * differently. I think Chet's interpretation of the spec is the most reasonable (but you could argue otherwise): http://lists.gnu.org/archive/html/bug-bash/2013-01/msg00180.html Most script writers treat assignments as identical whether quoted or not. Quotes should only be needed to assign whitespace-containing strings and $'...' quotes, but shouldn't affect globbing or word splitting or modify the expansion in any other way. You'll notice the same thing in the case of herestrings. $ mksh -c 'set one:::two three:::four; IFS=:; cat <<<$@' one:::two:three:::four $ mksh -c 'set one:::two three:::four; IFS=:; cat <<<"$@"' one:::two:three:::four $ ksh -c 'set one:::two three:::four; IFS=:; cat <<<"$@"' one:::two three:::four $ ksh -c 'set one:::two three:::four; IFS=:; cat <<<$@' one:::two three:::four $ bash -c 'set one:::two three:::four; IFS=:; cat <<<$@' one two three four $ bash -c 'set one:::two three:::four; IFS=:; cat <<<"$@"' one:::two three:::four I tend to think AT&T ksh is doing the most reasonable thing here by making the concatenated result exactly the same as if expanded as arguments in a quoted context, with whitespace separating them. > In other words, “don’t do that then” (rely on this behaviour). I wouldn't bother with this language if the only non-random behavior was that specified by POSIX. "POSIX doesn't specify it" is a horrible reason to do anything. > I think eval is evil anyway ;-) Eval is frowned upon because it almost always misused. Until shells add first- class closures and higher-order functions I'll continue using it. > (Thanks to ormaaj for pointing out this posting.) :) -- Dan Douglas