backslashes in output of command substitution trigger GLOB
Configuration Information [Automatically generated, do not change]: Machine: x86_64 OS: linux-gnu Compiler: gcc Compilation CFLAGS: -g -O2 -fdebug-prefix-map=/build/bash-a6qmCk/bash-5.0=. -fstack-protector-strong -Wformat -Werror=format-security -Wall -Wno-parentheses -Wno-format-security uname output: Linux idallen-oak 5.4.0-48-generic #52-Ubuntu SMP Thu Sep 10 10:58:49 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux Machine Type: x86_64-pc-linux-gnu Bash Version: 5.0 Patch Level: 17 Release Status: release Description: If a word in the output of a command substitution contains a backslash, and the word (without backslash) happens to match a file name, the shell will replace the word with the file name. The backslashes will disappear. If the word doesn't match a file name, the backslashes are preserved. Backslashes are not GLOB characters. This matching should not happen. Turn on "shopt -s failglob". Now, if a word in the output of a command substitution contains a backslash, and the word (without the backslash) doesn't match a filename, bash gives a GLOB "no match" error. Backslashes are not GLOB characters. This error should not happen. I noticed this bug because many of the bash completion scripts don't work for me because I use "shopt -s failglob" in my .bashrc and many of the completion scripts don't properly quote to protect against GLOB expansion. I saw a "no match" error for a word that didn't have any GLOB characters in it, but did have a backslash. Bug found. Repeat-By: # Run "bash --norc" and enter an empty directory and do these things below. # The first section runs without failglob; the second section with. # The unexpected output is flagged with "NOT EXPECTED" below. bash-5.0$ shopt -u failglob bash-5.0$ echo '\a' >/tmp/foo # create a file with just \a in it bash-5.0$ echo \a a bash-5.0$ echo $(echo '\a') \a bash-5.0$ echo $(cat /tmp/foo) \a bash-5.0$ touch a bash-5.0$ echo $(echo '\a') a<=== NOT EXPECTED! bash-5.0$ echo $(cat /tmp/foo) a<=== NOT EXPECTED! bash-5.0$ echo $(echo '\a\b\c\d\e\f') \a\b\c\d\e\f bash-5.0$ touch abcdef bash-5.0$ echo $(echo '\a\b\c\d\e\f') abcdef <=== NOT EXPECTED bash-5.0$ shopt -s failglob bash-5.0$ rm * bash-5.0$ echo \a a bash-5.0$ echo $(echo '\a') bash: no match: \a <=== NOT EXPECTED! bash-5.0$ echo $(cat /tmp/foo) bash: no match: \a <=== NOT EXPECTED! bash-5.0$ touch a bash-5.0$ echo $(echo '\a') a<=== NOT EXPECTED! bash-5.0$ echo $(cat /tmp/foo) a<=== NOT EXPECTED! bash-5.0$ echo $(echo '\a\b\c\d\e\f') bash: no match: \a\b\c\d\e\f <=== NOT EXPECTED! bash-5.0$ touch abcdef bash-5.0$ echo $(echo '\a\b\c\d\e\f') abcdef <=== NOT EXPECTED
commands do not ignore TSTP if TSTP ignored already
Configuration Information [Automatically generated, do not change]: Machine: x86_64 OS: linux-gnu Compiler: gcc Compilation CFLAGS: -DPROGRAM='bash' -DCONF_HOSTTYPE='x86_64' -DCONF_OSTYPE='linux-gnu' -DCONF_MACHTYPE='x86_64-pc-linux-gnu' -DCONF_VENDOR='pc' -DLOCALEDIR='/usr/share/locale' -DPACKAGE='bash' -DSHELL -DHAVE_CONFIG_H -I. -I../bash -I../bash/include -I../bash/lib -D_FORTIFY_SOURCE=2 -g -O2 -fstack-protector --param=ssp-buffer-size=4 -Wformat -Wformat-security -Werror=format-security -Wall uname output: Linux idallen-oak.home.idallen.ca 3.13.0-37-generic #64~precise1-Ubuntu SMP Wed Sep 24 21:37:11 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux Machine Type: x86_64-pc-linux-gnu Bash Version: 4.2 Patch Level: 25 Release Status: release Description: If a bash shell script starts up with TSTP ignored, commands run by that script will not ignore TSTP, even if you set a trap in the script to ignore TSTP. If the script starts up with TSTP not ignored, then the trap to ignore TSTP works fine. Repeat-By: Create these two scripts below one.sh and two.sh and run ./one.sh and use ^Z to signal TSTP. The "sleep" will stop, even though TSTP is ignored. Remove (comment out) the "trap" line from one.sh and run ./one.sh and now ^Z (TSTP) is properly ignored when two.sh runs. ==> one.sh <== #!/bin/bash trap '' TSTP exec ./two.sh ==> two.sh <== #!/bin/bash trap '' TSTP while : ; do echo "DEBUG" sleep 1 done
unexpected tilde quoting change in version 4.3
Bash Version: 4.2 and 4.3 Description: I find this change in quoting from 4.2 to 4.3 odd, where double-quoted "~" used to be quoted (no expansion) and no longer works: Bash version 4.2.25(1)-release: $ x=foo $ y="${x/foo/\~}" # backslash is more than is needed $ echo "$y" \~ $ y="${x/foo/~}"# double quotes work $ echo "$y" ~ $ y=${x/foo/\~} # backslash also works $ echo "$y" ~ $ y=${x/foo/~} # expands (okay) $ echo "$y" /home/idallen Bash 4.3 takes extra work to hide the tilde: $ x=foo $ y="${x/foo/\~}"# need both double quotes *and* backslash !? $ echo "$y" ~ $ y="${x/foo/~}" # doesn't quote any more (worked in 4.2) $ echo "$y" /home/idallen $ y=${x/foo/\~} # quotes same as 4.2 $ echo "$y" ~ $ y=${x/foo/~} # expands same as 4.2 $ echo "$y" /home/idallen Is this an intentional change?
set -o notify spurious CR when jobs redirected to file
Configuration Information [Automatically generated, do not change]: Machine: x86_64 OS: linux-gnu Compiler: gcc Compilation CFLAGS: -DPROGRAM='bash' -DCONF_HOSTTYPE='x86_64' -DCONF_OSTYPE='linux-gnu' -DCONF_MACHTYPE='x86_64-pc-linux-gnu' -DCONF_VENDOR='pc' -DLOCALEDIR='/usr/share/locale' -DPACKAGE='bash' -DSHELL -DHAVE_CONFIG_H -I. -I../bash -I../bash/include -I../bash/lib -D_FORTIFY_SOURCE=2 -g -O2 -fstack-protector --param=ssp-buffer-size=4 -Wformat -Wformat-security -Werror=format-security -Wall uname output: Linux idallen-oak.home.idallen.ca 3.13.0-40-generic #68~precise1-Ubuntu SMP Tue Nov 4 16:00:24 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux Machine Type: x86_64-pc-linux-gnu Bash Version: 4.2 Patch Level: 25 Release Status: release Description: Using "set -o notify" adds spurious CR to output of "jobs" when output is redirected to a file (but not into a pipe). Repeat-By: $ sleep 999 & [1] 16386 $ set +o notify $ jobs >out $ file out out: ASCII text $ set -o notify $ jobs >out $ file out out: ASCII text, with CRLF line terminators $ od -c out 000 [ 1 ] + R u n n i n g 020 s l 040 e e p 9 9 9 & \r \n 053 $ jobs | od -c 000 [ 1 ] + R u n n i n g 020 s l 040 e e p 9 9 9 & \n 052
filename TAB completion breaks using "force write" redirection syntax
Configuration Information [Automatically generated, do not change]: Machine: x86_64 OS: linux-gnu Compiler: gcc Compilation CFLAGS: -DPROGRAM='bash' -DCONF_HOSTTYPE='x86_64' -DCONF_OSTYPE='linux-gnu' -DCONF_MACHTYPE='x86_64-pc-linux-gnu' -DCONF_VENDOR='pc' -DLOCALEDIR='/usr/share/locale' -DPACKAGE='bash' -DSHELL -DHAVE_CONFIG_H -I. -I../. -I.././include -I.././lib -D_FORTIFY_SOURCE=2 -g -O2 -fstack-protector-strong -Wformat -Werror=format-security -Wall uname output: Linux idallen-oak 3.19.0-20-generic #20-Ubuntu SMP Fri May 29 10:10:47 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux Machine Type: x86_64-pc-linux-gnu Bash Version: 4.3 Patch Level: 30 Release Status: release Description: I don't know if this bug applies to bash or to bash-completion. Reference: "man bash" section "Redirecting Output" Filename TAB completion breaks using "force write" redirection syntax. The use of the "pipe" symbol after the ">" makes the completion think that a command name is required instead of a file name. Repeat-By: $ cd /tmp $ touch foobar $ set -o noclobber $ date > foo foobar # this is expanded correctly to the file name bash: foobar: cannot overwrite existing file # this is correct $ date >| foo # using overwrite syntax triggers command name expansion foo2hbpl2 foo2lava-wrapperfoo2xqx foo2hbpl2-wrapper foo2oak foo2xqx-wrapper foo2hiperc foo2oak-wrapper foo2zjs foo2hiperc-wrapper foo2qpdlfoo2zjs-icc2ps@ foo2hp foo2qpdl-wrapperfoo2zjs-pstops foo2hp2600-wrapper foo2slx foo2zjs-wrapper foo2lavafoo2slx-wrapper foomatic-rip@ The pathnames matched by ">" and ">|" should be identical.
local keyword hides return code of command substitution
Configuration Information [Automatically generated, do not change]: Machine: x86_64 OS: linux-gnu Compiler: gcc Compilation CFLAGS: -DPROGRAM='bash' -DCONF_HOSTTYPE='x86_64' -DCONF_OSTYPE='linux-gnu' -DCONF_MACHTYPE='x86_64-pc-linux-gnu' -DCONF_VENDOR='pc' -DLOCALEDIR='/usr/share/locale' -DPACKAGE='bash' -DSHELL -DHAVE_CONFIG_H -I. -I../. -I.././include -I.././lib -D_FORTIFY_SOURCE=2 -g -O2 -fstack-protector-strong -Wformat -Werror=format-security -Wall uname output: Linux idallen-oak 3.19.0-28-generic #30-Ubuntu SMP Mon Aug 31 15:52:51 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux Machine Type: x86_64-pc-linux-gnu Bash Version: 4.3 Patch Level: 30 Release Status: release Description: Adding a "local" keyword to a variable assignment hides the return code of a command substitution. Same problem in both bash and dash shells. The keyword may be operating as described in the man page, but it is highly non-intuitive that adding it would do this. The work-around is to use "local" to declare the variable first, then do the command substitution assignment on another line and check the return code there. If the behaviour of "local" can't be changed, perhaps the man page could warn about this? Repeat-By: Run this: #!/bin/bash -u # Using "local" keyword hides return code of command substitution. # Same problem in both bash and dash shells. # -Ian! D. Allen - idal...@idallen.ca - www.idallen.com Myfunc () { foo=$( false ) echo "return code should be 1: $?" local bar=$( false ) echo "return code should be 1: $?" } Myfunc
history separates >| and 2>&1 tokens when recalled with !*
Configuration Information [Automatically generated, do not change]: Machine: x86_64 OS: linux-gnu Compiler: gcc Compilation CFLAGS: -DPROGRAM='bash' -DCONF_HOSTTYPE='x86_64' -DCONF_OSTYPE='linux-gnu' -DCONF_MACHTYPE='x86_64-pc-linux-gnu' -DCONF_VENDOR='pc' -DLOCALEDIR='/usr/share/locale' -DPACKAGE='bash' -DSHELL -DHAVE_CONFIG_H -I. -I../. -I.././include -I.././lib -D_FORTIFY_SOURCE=2 -g -O2 -fstack-protector-strong -Wformat -Werror=format-security -Wall uname output: Linux idallen-oak 4.2.0-35-generic #40-Ubuntu SMP Tue Mar 15 22:15:45 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux Machine Type: x86_64-pc-linux-gnu Bash Version: 4.3 Patch Level: 42 Release Status: release Description: The history recall !* incorrectly pulls apart the >| and 2>&1 words, making them useless. Repeat-By: bash-4.3$ date >| /tmp/i bash-4.3$ who !* who > | /tmp/i bash: syntax error near unexpected token `|' bash-4.3$ date 2>&1 Thu Apr 21 19:24:46 EDT 2016 bash-4.3$ echo !* echo 2 >& 1 2
man page confusion about array with no members: var=()
Configuration Information [Automatically generated, do not change]: Machine: x86_64 OS: linux-gnu Compiler: gcc Compilation CFLAGS: -DPROGRAM='bash' -DCONF_HOSTTYPE='x86_64' -DCONF_OSTYPE='linux-gnu' -DCONF_MACHTYPE='x86_64-pc-linux-gnu' -DCONF_VENDOR='pc' -DLOCALEDIR='/usr/share/locale' -DPACKAGE='bash' -DSHELL -DHAVE_CONFIG_H -I. -I../. -I.././include -I.././lib -Wdate-time -D_FORTIFY_SOURCE=2 -g -O2 -fstack-protector-strong -Wformat -Werror=format-security -Wall uname output: Linux idallen-oak 4.4.0-28-generic #47-Ubuntu SMP Fri Jun 24 10:09:13 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux Machine Type: x86_64-pc-linux-gnu Bash Version: 4.3 Patch Level: 46 Release Status: release Description: The BASH man pags says "When there are no array members, ${name[@]} expands to nothing." and then later "An array variable is considered set if a subscript has been assigned a value.". The first sentence tells me that ${name[@]} is a valid use of a variable that exists but has no members, but the second sentence implies that if the array has no members it is considered "unset" and thus ${name[@]} would not be a valid use of the name. These are contradictory statements. Using ${name[@]} with no array members generates an "unbound variable" error under "nounset"; it does not expand to "nothing". The reason ${name[@]} expands to nothing is not because it's a valid use of ${name[@]}, it's because any use of an unset variable expands to nothing, unless, as I do, you run with "nounset" enabled and it causes an error. To fit current behaviour, the first man page sentence above should be changed to say: When there are no array members, the array name is considered unset and ${name[@]} will expand to nothing or generate an "unbound variable" error under the "nounset" option. I'd prefer that BASH change the behaviour of var=() to not give an "unbound variable" error on ${name[@]}, but changing the man page is probably easier than changing the current behaviour. Repeat-By: #!/bin/bash -u # make BASH complain about unset variables set -o nounset echo 'ONE: set var= and try $var and ${var[@]} - both work without error' unset var var= ( echo "ONE: [$var]" ) ( echo "ONE: [${var[@]}]" ) echo 'TWO: set var=() and try again - both fail with "unbound variable"' unset var var=() ( echo "TWO: [$var]" ) ( echo "TWO: [${var[@]}]" )
built-in commands give no syntax error on trailing garbage
Configuration Information [Automatically generated, do not change]: Machine: x86_64 OS: linux-gnu Compiler: gcc Compilation CFLAGS: -DPROGRAM='bash' -DCONF_HOSTTYPE='x86_64' -DCONF_OSTYPE='linux-gnu' -DCONF_MACHTYPE='x86_64-pc-linux-gnu' -DCONF_VENDOR='pc' -DLOCALEDIR='/usr/share/locale' -DPACKAGE='bash' -DSHELL -DHAVE_CONFIG_H -I. -I../. -I.././include -I.././lib -Wdate-time -D_FORTIFY_SOURCE=2 -g -O2 -fstack-protector-strong -Wformat -Werror=format-security -Wall uname output: Linux idallen-oak 4.4.0-36-generic #55-Ubuntu SMP Thu Aug 11 18:01:55 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux Machine Type: x86_64-pc-linux-gnu Bash Version: 4.3 Patch Level: 46 Release Status: release Description: Many built-in commands ignore trailing garbage instead of giving a syntax error, and this leads newbies into making dumb mistakes that they think work fine because of no error message, e.g.: $ umask 0777 myfile # should have been chmod $ cd /usr /bin# goes to /usr not to intended /usr/bin Commands should never ignore user input. If it's there, someone thinks it should be used. Use it or please give error messages. Repeat-By: $ cd /bin this trailing garbage is ignored but should give an error $ pushd /bin this trailing garbage is ignored but should give an error $ umask 022 this trailing garbage is ignored but should give an error $ help help this trailing garbage is ignored but should give an error etc. Fix: Make built-in commands give error messages if given too many arguments.
PWD not made canonical on shell start
Configuration Information [Automatically generated, do not change]: Machine: x86_64 OS: linux-gnu Compiler: gcc Compilation CFLAGS: -DPROGRAM='bash' -DCONF_HOSTTYPE='x86_64' -DCONF_OSTYPE='linux-gnu' -DCONF_MACHTYPE='x86_64-pc-linux-gnu' -DCONF_VENDOR='pc' -DLOCALEDIR='/usr/share/locale' -DPACKAGE='bash' -DSHELL -DHAVE_CONFIG_H -I. -I../. -I.././include -I.././lib -Wdate-time -D_FORTIFY_SOURCE=2 -g -O2 -fstack-protector-strong -Wformat -Werror=format-security -Wall uname output: Linux idallen-oak 4.4.0-78-generic #99-Ubuntu SMP Thu Apr 27 15:29:09 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux Machine Type: x86_64-pc-linux-gnu Bash Version: 4.3 Patch Level: 48 Release Status: release Description: In both BASH and DASH the shell variable $PWD is not always set by the shell on start-up to be the actual absolute path to the current directory. If PWD is passed in via the environment, it is used *as-is* as long as it is an absolute path and whatever directory it resolves to is the *same* as the current directory. This means you can pass in some crazy /././ and /../../../ pathnames via PWD and the shell will use them as-is. I know that PWD can contain symlinks, if set with the "cd" command and "physical" is turned off. (And I see that "physical" isn't even an option in DASH.) But nothing documents how /././ and /../../ can ever appear in PWD, so these things shouldn't be allowed to enter PWD via the environment. As shown below, you can pass in values of PWD that cannot be set using the "cd" command inside the shell itself. The examples below that are full of /././ and /../../ crap are especially troubling, since there is no way to use the "cd" command to set these values inside the shell, and the man page says that PWD is set by the "cd" command, so having values in PWD that can't be set using "cd" is wrong. I think it a bug that /././ and /../../ pathnames passed in via PWD are not cleaned up on shell start-up. You could make a case that a PWD containing symlinks should be allowed in from the environment, (unless -o physical) but surely not /././ and /../../ in pathnames? The shell should do the equivalent of "cd ." to clean up PWD at start-up. The man page doesn't say what happens with PWD if it is passed in via the environment. If you're going to keep the current behaviour, please document it, since the environment allows messy values in PWD that are unlike anything the shell does with the "cd" command. Not what I was expecting, at all. As implemented, I now have to start every shell script that uses $PWD before using "cd" with either 'cd "$(/bin/pwd)"' or 'set -o physical ; cd .' to get PWD into a usable state. Repeat-By: $ cat i.sh #!/bin/bash -u echo "$PWD" $ unset PWD $ printenv PWD $ ./i.sh /home/idallen $ PWD=crap ./i.sh /home/idallen $ PWD=/./././././home/././././idallen/./././. ./i.sh /./././././home/././././idallen/./././. $ ln -s /home/idallen /tmp/foo $ PWD=/tmp/foo ./i.sh /tmp/foo $ PWD=/../../../../tmp/foo ./i.sh /../../../../tmp/foo