Incorrect handling of echo in POSIX mode
Configuration Information [Automatically generated, do not change]: Machine: x86_64 OS: darwin19.6.0 Compiler: gcc Compilation CFLAGS: -g -O2 uname output: Darwin hemma.home 19.6.0 Darwin Kernel Version 19.6.0: Tue Jun 21 21:18:39 PDT 2022; root:xnu-6153.141.66~1/RELEASE_X86_64 x86_64 Machine Type: x86_64-apple-darwin19.6.0 Bash Version: 5.2 Patch Level: 26 Release Status: release Description: In POSIX mode, echo incorrectly processes -e as an option unless xpg_echo is also enabled. This is a regression from 3.2 (or possibly some 4.x versions, haven't tested), where --posix caused -e to be treated correctly, even if it also enabled backslash processing. ~ % /bin/bash --posix [macOS warning elided] bash-3.2$ echo -e foo\\nbar -e foo bar Repeat-By: ~/bash % bash bash-5.2$ bash --posix -c 'echo -e foo\\nbar' foo bar bash-5.2$ bash --posix -O xpg_echo -c 'echo -e foo\\nbar' -e foo bar -- Clint Hepner
read with parameter expansion in here string
Configuration Information [Automatically generated, do not change]: Machine: i386 OS: darwin13.0.0 Compiler: clang Compilation CFLAGS: -DPROGRAM='bash' -DCONF_HOSTTYPE='i386' -DCONF_OSTYPE='darwin13.0.0' -DCONF_MACHTYPE='i386-apple-darwin13.0\ .0' -DCONF_VENDOR='apple' -DLOCALEDIR='/usr/local/Cellar/bash/4.2.45/share/locale' -DPACKAGE='bash' -DSHELL -DHAVE_CONFIG_H -DMA\ COSX -I. -I. -I./include -I./lib -I./lib/intl -I/private/tmp/bash-4vKN/bash-4.2/lib/intl -DSSH_SOURCE_BASHRC uname output: Darwin patikoija.local 13.0.0 Darwin Kernel Version 13.0.0: Thu Sep 19 22:22:27 PDT 2013; root:xnu-2422.1.72~6/REL\ EASE_X86_64 x86_64 Machine Type: i386-apple-darwin13.0.0 Bash Version: 4.2 Patch Level: 45 Release Status: release Description: An unquoted parameter expansion in a here string does not seem to conform with my understanding of how read works with a local IFS override. Personally observed in bash 3.2.51, 4.1.2 as well. I first learned of this possible bug via http://stackoverflow.com/q/20144593/1126841. Repeat-By: $ var="hello:world" # Case (1) I would expect "hello:world" in var1 if $var isn't split, or "hello" # if it is. World splitting seems to occur after var1 is set, which doesn't # seem to make sense. $ IFS=: read var1 var2 <<< $var $ echo "$var1" hello world # Case (2) Expected behavior, consistent with case (3) $ IFS=: read var1 var2 <<< "$var" $ echo "$var1" hello # Case (3) - no parameter expansion involved with the read $ IFS=: read var1 var2 <<< hello:world $ echo "$var1" hello # Case (4) - an explicit here document instead of a here string $ IFS=: read var1 var2 < $var > EOF $ echo "$var1" hello
Re: read with parameter expansion in here string
On Nov 22, 2013, at 10:04 AM, Pierre Gaston wrote: > > > > On Fri, Nov 22, 2013 at 4:22 PM, Clint Hepner wrote: > Configuration Information [Automatically generated, do not change]: > Machine: i386 > OS: darwin13.0.0 > Compiler: clang > Compilation CFLAGS: -DPROGRAM='bash' -DCONF_HOSTTYPE='i386' > -DCONF_OSTYPE='darwin13.0.0' -DCONF_MACHTYPE='i386-apple-darwin13.0\ > .0' -DCONF_VENDOR='apple' > -DLOCALEDIR='/usr/local/Cellar/bash/4.2.45/share/locale' -DPACKAGE='bash' > -DSHELL -DHAVE_CONFIG_H -DMA\ > COSX -I. -I. -I./include -I./lib -I./lib/intl > -I/private/tmp/bash-4vKN/bash-4.2/lib/intl -DSSH_SOURCE_BASHRC > uname output: Darwin patikoija.local 13.0.0 Darwin Kernel Version 13.0.0: Thu > Sep 19 22:22:27 PDT 2013; root:xnu-2422.1.72~6/REL\ > EASE_X86_64 x86_64 > Machine Type: i386-apple-darwin13.0.0 > > Bash Version: 4.2 > Patch Level: 45 > Release Status: release > > Description: > > An unquoted parameter expansion in a here string does not seem to > conform with my understanding of how > read works with a local IFS override. Personally observed in bash > 3.2.51, 4.1.2 as well. I first learned > of this possible bug via http://stackoverflow.com/q/20144593/1126841. > > Repeat-By: > $ var="hello:world" > > # Case (1) I would expect "hello:world" in var1 if $var isn't split, > or "hello" > # if it is. World splitting seems to occur after var1 is set, which > doesn't > # seem to make sense. > $ IFS=: read var1 var2 <<< $var > $ echo "$var1" > hello world > > $var is split on : and the expansion results in "hello world" which doesn't > contains a :, so var1 gets "hello world" > but yeah, this is a bit of a grey zone > Looking at the change log at http://tiswww.case.edu/php/chet/bash/CHANGES, I noticed item (jj) in the changes to bash 4.1 alpha: jj. Fixed a bug that caused variable expansion in here documents to look in any temporary environment. And I can observe that between bash 3.2 and bash 4.1: bash-3.2 $ FOO=foo; FOO=bar cat <<< "$FOO" bar bash-4.1 $ FOO=foo; FOO=bar cat <<< "$FOO" foo However, why is the new value of IFS applied to the expansion of $var, instead of the current? Shouldn't read get the literal string "hello:world" from the here string? And if $var is split, why doesn't this expression work the same as $ read var1 var2 <<< hello world which is equivalent to $ read var1 var2 world <<< hello The following works as expected, which implies that the new value of IFS is being applied prematurely, but the quotes protect the colon from causing splitting and being removed until "hello:world" can be properly split inside the read builtin. $ IFS=: read var1 var2 <<< "$var"
Documentation for declare/typeset does not address +=
Configuration Information [Automatically generated, do not change]: Machine: i386 OS: darwin13.0.0 Compiler: clang Compilation CFLAGS: -DPROGRAM='bash' -DCONF_HOSTTYPE='i386' -DCONF_OSTYPE='darwin13.0.0' -DCONF_MACHTYPE='i386-apple-darwin13.0.0' -DCONF_VENDOR='apple' -DLOCALEDIR='/usr/local/Cellar/bash/4.2.45/share/locale' -DPACKAGE='bash' -DSHELL -DHAVE_CONFIG_H -DMACOSX -I. -I. -I./include -I./lib -I./lib/intl -I/private/tmp/bash-4vKN/bash-4.2/lib/intl -DSSH_SOURCE_BASHRC uname output: Darwin patikoija.local 13.0.0 Darwin Kernel Version 13.0.0: Thu Sep 19 22:22:27 PDT 2013; root:xnu-2422.1.72~6/RELEASE_X86_64 x86_64 Machine Type: i386-apple-darwin13.0.0 Bash Version: 4.2 Patch Level: 45 Release Status: release Description: The following code appears to work as expected: array=(a b c) a=array declare "$a+=(d) # array is now (a b c d) I assume this is intentional and in keeping with how += works, but the entry for declare/typeset in the man page only addresses the case where the variable name is followed by =value. Fix: Mention += in the entry for declare/typeset, or otherwise clarify how the builtin works.
Re: Spaces trimmed from $* when assigned while IFS is unset [was: Unexpected word splitting on $* ...]
On Wed, Sep 27, 2017 at 9:10 AM, Martijn Dekker wrote: > Op 27-09-17 om 14:44 schreef Greg Wooledge: > > I'm just going to chalk this up as yet another example of unquoted $* > > or $@ being Completely Wrong. > > Nonsense. This is a bug in bash and it should be fixed, not excused. > Quoting expansions should never be necessary for assignments. For what its worth, this behavior appears to have been introduced in bash 4.3: % cat tmp.bash set " abc " " def ghi " "jkl " unset -v IFS var var=${var-$*}/${var-$*} printf '[%s]\n' "$var" % for tag in 3.2 4.0 4.1 4.2 4.3 4.4; do echo "$tag"; docker run -i bash:$tag bash < tmp.bash; done 3.2 [ abcdef ghi jkl / abcdef ghi jkl ] 4.0 [ abcdef ghi jkl / abcdef ghi jkl ] 4.1 [ abcdef ghi jkl / abcdef ghi jkl ] 4.2 [ abcdef ghi jkl / abcdef ghi jkl ] 4.3 [abc def ghi jkl/abc def ghi jkl] 4.4 [abc def ghi jkl/abc def ghi jkl]
Re: Enabling History Expansion with `set -H'.
> On 2018 Jan 21 , at 7:13 a, Ralph Corderoy wrote: > > Hi, > > Please keep me CC'd. > > bash package 4.4.012-2 on Arch Linux, > `version 4.4.12(1)-release (x86_64-unknown-linux-gnu)'. > > I'm trying to enable history expansion in a non-interactive bash with > `set -H'. > >$ printf '%s\n' ': foo' 'echo !!' 'set -H' ': bar' 'echo !!' | >> bash >!! >!! >$ > > I'd expect the second `!!' to be `: bar'. > What am I misunderstanding? You enabled history *expansion*, but not the history mechanism itself, so there is nothing for !! to expand to. You need `set -o history` as well. $ printf '%s\n' ': foo' 'echo !!' 'set -H -o history' ': bar' 'echo !!' | bash !! echo : bar : bar The second line, 'echo : bar', is the result of the expansion itself, prior to the resulting command actually being executed.
Re: Unset array doesn't work
> On 2018 Feb 26 , at 4:31 a, Robert Elz wrote: > >Date:Mon, 12 Feb 2018 09:26:37 -0500 >From:Chet Ramey >Message-ID: <790ade74-690f-541c-9ab4-635991744...@case.edu> > > | This is bash's dynamic scoping. The visibility of a local variable is > | restricted to a function and its children, and `unset' removes the > | currently-visible instance. Removing such an instance can `unconver' an > | instance in a previous scope. > > Frankly this is brain dead, unset should not be unlocal (or something equiv) > > eg: if I have a func > > myfunc() { > local IFS > unset IFS > # do some code > } > > the very last thing that I want is for the global IFS to apply. > > The intent is to use the default IFS value, which is what an unset IFS > produces, without affecting the current global IFS setting. As you say, the intent is to use a particular value of the variable. The fact that unsetting IFS causes it to use a default value other than an empty string seems more like a concession to historical usage than a feature that should be explicitly used. If you need a particular value, assign it instead of using a nonobvious alternative that is only shorter by three of characters: IFS=$' \t\n' unset IFS > In this example, I could do IFS=$' \t\n' if I was willing to assume that > $'...' > support exists (the shell executing the script is not necessarily going to > be bash) You are already assuming $'...'-support if you are using local; both are bash extensions to the POSIX standard. If portability is your goal, making a nonstandard change to one shell isn't going to help. Suppose bash did change the behavior of unset (even optionally) or added an "unlocal" command, and you made use of this. Now your script is limited to bash 4.5 or newer, and *maybe* any other shell that could be convinced to implement something similar. $'...' already enjoys wider level of support. > or I could do > > IFS=' > ' > > and just hope that survives as written (it would straight from the editor, > but who knows when someone else decides that trailing whitespace on > lines should all be deleted). Variants to avoid that get even uglier. People who remove whitespace from inside quotes do so at their own risk. Not all trailing whitespace is extraneous. If necessary, you can define a global (at the expense of a single subprocess) myIFS=$(printf ' \t\n') to get a value in a completely POSIX-compatible way you can use to assign to a localized copy of IFS. (But I want to reiterate that you have already thrown POSIX compatibility out the window by using local in the first place, so you might as well use $' \t\n'.) -- Clint
Re: bash long prompt, color going past the end of prompt after reaching bottom of terminal
> On 2018 Mar 23 , at 8:26 a, Greg Wooledge wrote: > > On Fri, Mar 23, 2018 at 12:36:22AM +0200, Ilkka Virta wrote: >> I get the same with '4.4.12(1)-release' too, but it doesn't seem related to >> Bash or the prompt. I can get it with just a printf, the colored part just >> needs to get wrapped by the end of line. >> >> printf "%100s $(tput setab 1)colored part$(tput sgr0) normal again\n" >> >> If the screen scrolls, the background color on the last character gets >> copied to the next line. > > Ahh. In that case, it's a bug (or undesired feature) of your terminal > emulator, and you should address the bug reports in that direction. > I can reproduce buggy appearance in the following, all running on macOS: * iTerm2 * Terminal * The console of a CentOS 7 VM running in Virtual Box Adapting the original function to work with zsh, # Changes: # \w -> %~ # \[...\] -> %{...%} # \$ -> %# calculate_prompt1() { host="my-linux" git_branch="a very very very very very very very very very very very very very very long prompt" prompt="@$host %~ : %{$(tput bold)$(tput setab 1)$(tput setaf 7)%}${git_branch}%{$(tput sgr0)%}%# " export PS1="$prompt" } I cannot reproduce in any of the three environments listed above. Clint
Re: Number with sign is read as octal despite a leading 10#
The + is a unary operator, not part of the literal. Write $((+10#0034)) instead. -- Clint On Jul 9, 2018, 9:24 PM -0400, Isaac Marcos , wrote: > 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 > uname output: Linux IO 4.9.0-6-amd64 #1 SMP Debian 4.9.88-1+deb9u1 > (2018-05-07) x86_64 GNU/Linux > Machine Type: x86_64-pc-linux-gnu > > Bash Version: 4.4 > Patch Level: 12 > Release Status: release > > Description: > A value inside an arithmetic expansion is processed as octal despite using > a 10# preffix. > > Repeat-By: > $ echo $((10#+0034)) > 28 > > Fix: > Extract optional sign before parsing the number, re-attach after. > > -- > Cases are always threesome: > Best case, Worst case, and Just in case
Re: [1] 69728 segmentation fault bash
> On 2018 Jul 20 , at 9:27 a, Mr Guiguilebreton wrote: > > Hello, check this command in GNU bash, version 3.2.57(1)-release > (x86_64-apple-darwin17): > > ls () { ls -lG;}; ls You wrote a recursive function with no base case. Don't do that. ls () { command ls -lG; }; ls or use an alias for one of its few legitimate use cases alias ls='ls -lG'
Re: [1] 69728 segmentation fault bash
> On 2018 Jul 20 , at 10:40 a, Mr Guiguilebreton wrote: > > Yes, i now. I test the syntax and the parse error because I programming a > command interpreter bash in C language and I report the Segmentation Fault > for help you to debug. If you want I can help you free to solve the problem. See https://lists.gnu.org/archive/html/bug-bash/2017-09/msg00048.html. > > > freely, > Guillaume Madec > (+33)6 46 01 00 79 > > 2018-07-20 16:17 GMT+02:00 Clint Hepner : > > > On 2018 Jul 20 , at 9:27 a, Mr Guiguilebreton wrote: > > > > Hello, check this command in GNU bash, version 3.2.57(1)-release > > (x86_64-apple-darwin17): > > > > ls () { ls -lG;}; ls > > You wrote a recursive function with no base case. Don't do that. > > ls () { command ls -lG; }; ls > > or use an alias for one of its few legitimate use cases > > alias ls='ls -lG' >
Tilde expansion in assignment-like context
Configuration Information [Automatically generated, do not change]: Machine: x86_64 OS: darwin16.7.0 Compiler: clang Compilation CFLAGS: -DPROGRAM='bash' -DCONF_HOSTTYPE='x86_64' -DCONF_OSTYPE='d\ arwin16.7.0' -DCONF_MACHTYPE='x86_64-apple-darwin16.7.0' -DCONF_VENDOR='apple' \ -DLOCALEDIR='/usr/local/Cellar/bash/4.4.19/share/locale' -DPACKAGE='bash' -DSHE\ LL -DHAVE_CONFIG_H -DMACOSX -I. -I. -I./include -I./lib -I./lib/intl -I/priv\ ate/tmp/bash-20180209-55597-111ek7c/bash-4.4/lib/intl -DSSH_SOURCE_BASHRC -Wno\ -parentheses -Wno-format-security uname output: Darwin hemma.local 16.7.0 Darwin Kernel Version 16.7.0: Thu Jun 2\ 1 20:07:39 PDT 2018; root:xnu-3789.73.14~1/RELEASE_X86_64 x86_64 Machine Type: x86_64-apple-darwin16.7.0 Bash Version: 4.4 Patch Level: 19 Release Status: release Description: A non-initial unquoted tilde is expanded outside of an assignment. This was raised as a question on Stack Overflow, https://stackoverflow.com/q/51713759/1126841. Repeat-By: $ set +k $ echo home_dir=~ home_dir=/Users/chepner A similar string that does not start with a valid identifier leaves the tilde unexpanded. $ echo --home_dir=~ --home_dir=~ The behavior is also present in commit 057a9fbdb4d9ad01b000743fcea9918b80823afc, bash-20180803 snapshot. Fix: [Description of how to fix the problem. If you don't know a fix for the problem, don't include this section.]
Re: Tilde expansion in assignment-like context
> On 2018 Aug 6 , at 3:45 p, Chet Ramey wrote: > > On 8/6/18 3:09 PM, Clint Hepner wrote: > >> Bash Version: 4.4 >> Patch Level: 19 >> Release Status: release >> >> Description: >>A non-initial unquoted tilde is expanded outside of an assignment. >> This >>was raised as a question on Stack Overflow, >> https://stackoverflow.com/q/51713759/1126841. >> >> Repeat-By: >> >>$ set +k >>$ echo home_dir=~ >>home_dir=/Users/chepner > > Yes. Bash has done this since its earliest days. A word that looks like an > assignment statement has tilde expansion performed after unquoted =~ and :~ > no matter where it appears on the command line. This makes things like > > make DESTDIR=~stager/bash-install > or > export PATH=/usr/local/bin:~/bin:/usr/bin > > easy and convenient. Oh, right. For some reason, I had it in my head that this was only intended for builtins like export, and that their status as builtins somehow made the argument be treated as an assignment. I hadn't thought at all about non-builtin commands like make. > > The first version I can find that implemented the =~ and :~ tilde expansion > prefixes is bash-1.10 (1991). Those early versions would have expanded > something like `--home_dir=~'. The first version that restricted it to > words that satisfied the assignment statement restrictions is bash-2.0 > (1996). > > Bash doesn't do this when it's in posix mode. The first version that > implemented that was bash-1.14.0. > > -- > ``The lyf so short, the craft so long to lerne.'' - Chaucer >``Ars longa, vita brevis'' - Hippocrates > Chet Ramey, UTech, CWRUc...@case.eduhttp://tiswww.cwru.edu/~chet/
Re: Add sleep builtin
> On Aug 19, 2018, at 10:25 AM, konsolebox wrote: > > Hi Chet, > > The sleep command is often used in loops and using the external sleep > is expensive. Expensive is relative, as the time spent actually sleeping probably dwarfs the startup time. If not, you probably want to find an alternative to polling anyway. Clint
Re: x[
> On 2019 Jul 29 , at 12:55 p, Isabella Bosia wrote: > > haven't really looked into why this happens but x[ seems to trigger some > funny parser behavior > > x[ newline should not prompt with PS2 > > it can't be defined as a normal sh function, but it can be defined with the > function keyword > > it can't be called like a normal function, but things like "x[" or \x[ work > > this bug seems old The ``[`` begins a valid shell pattern, so the parser continues to accept input until the closing ``]`` is found. Pathname expansion (apparently) does not apply to the first "argument" of the ``function`` command.
Re: [FR] save command times and exit status in history automatically
> On 2019 Nov 7 , at 3:18 p, Daniel Colascione wrote: > > On Thu, Nov 7, 2019 at 12:09 PM Chet Ramey wrote: >> >> On 11/5/19 12:49 PM, Daniel Colascione wrote: >>> Right now, bash history saves only the command line actually executed. >> >> This isn't quite the case. What it saves is the line returned from >> readline, before it's expanded or executed. > > Fair enough. > >>> Why not also, optionally, save command execution times and exit >>> statuses? This information is practically free to collect. >> >> Because by the time you gather this information, the command has already >> been saved completely. >> >> There have been various proposals to extend the timestamp with additional >> information, but it's all data you can gather when the timestamp is saved >> before the command is executed. > > That's how history works today, yes. I'm wondering whether it'd be > possible to maintain an auxiliary history that included not only the > command lines read, but also their execution time and outcome. Doing > something in PROMPT_COMMAND doesn't seem quite accurate. Maybe what I > really want is something like $?, but instead of containing exit > status, it would contain information from a struct rusage (derived > from wait4) for the last command. Or something like that anyway. The > larger point is that the shell could gather this information > proactively almost for free and I don't think user code running in > existing shell extension points can do the same job. > Conceptually, this is quite a leap. Right now, the history list doesn't require *any* effort beyond logging the input. What you are suggesting may be readily accessible, but it's still *additional* work that must be done. Furthermore, a few issues off the top of my head: * How would handle background jobs? Would they appear in the order they are started, or the order they are completed? * Suppose I start a loop like for x in 1 2 3; do someCommand "$x" done Do you want to store the result of the for loop? Each of the commands run in the loop? What would that look like? * Would you want some way of linking the result of a `wait -n` command with the command it waited for? What would that look like? * Would you want to store *any* output from a command in your log? I think the design of such a feature would require a lot of careful thought to be useful. -- Clint
Re: man bash does not list 'in' as a builtin command
> On 2019 Nov 25 , at 4:43 p, Peter Benjamin wrote: > > > Description: > 'in' is a builtin command and is not listed in the man page as such. > > Repeat-By: > > type at the bash command line: > > $ in > bash: syntax error near unexpected token `in' This should be a big hint that it is *not* a built-in command. If it were, you would have run the command, not gotten a syntax error. > > Why is this bug report important? Why change the man page? I wasted > 20 minutes of my time, to prove to my satisfaction that 'in' was not > invoking my script at all. Search engines did not find a match to the > error message. I can not imagine this report is the first time this > bug was found. Given that ``in'' *is* documented as a reserved word RESERVED WORDS Reserved words are words that have a special meaning to the shell. The following words are recognized as reserved when unquoted and either the first word of a simple command (see SHELL GRAMMAR below) or the third word of a case or for command: ! case coproc do done elif else esac fi for function if in select then until while { } time [[ ]] the question becomes, what change to the man page do you think would have helped you find this more quickly? One thing that comes to mind would be a short (though off-topic) entry in the SHELL BUILTIN COMMANDS section, like in See the Compound Commands section under SHELL GRAMMMAR. Used to form the ``case'', ``select'', and ``for'' commands. I don't really like that idea, as it starts down a slippery slope for adding all sorts of non-command entries, turning the section into a general glossary rather than a listing of built-in commands. Alternatively, maybe a short list of sections at the top of the man page would provide a hint. For example, imagine the man page started out like this: NAME bash - GNU Bourne-Again Shell SYNOPSIS bash [options] [command_string | file] DESCRIPTION Bash is [...] TABLE OF CONTENTS OPTIONS ARGUMENTS INVOCATION DEFINITIONS RESERVED WORDS SHELL GRAMMAR COMMENTS QUOTING PARAMETERS EXPANSION REDIRECTION ALIASES FUNCTIONS ARITHMETIC EVALUATION CONDITIONAL EXPRESSIONS SIMPLE COMMAND EXPANSION COMMAND EXECUTION COMMAND EXECUTION ENVIRONMENT ENVIRONMENT EXIT STATUS SIGNALS JOB CONTROL PROMPTING READLINE HISTORY HISTORY EXPANSION SHELL BUILTIN COMMANDS RESTRICTED SHELL SEE ALSO FILES AUTHORS BUG REPORTS BUGS OPTIONS All of the single-character shell options ... [etc] The table of contents inserted between the existing DESCRIPTION and OPTIONS sections is relatively brief, and both RESERVED WORDS and SHELL GRAMMAR seem like they would be good starting places to look for information about the ``in'' token mentioned in the syntax error. Given how short most of the section names are, it could easily be formatted as two columns, making it easier to scan. -- Clint
Re: Two states of empty arrays
On Thu, Dec 12, 2019 at 1:10 PM Léa Gris wrote: > Hello, > > Depending on how an empty array is declared, it is not stored with the > same state. > > # Empty array declared without parenthesis > unset myArr > declare -a myArr > typeset -p myArr > echo "${#myArr[@]}" > > output: > declare -a myArr > 0 > Here, you haven't yet defined a parameter named myArr; you have only set the array attribute on the name myArr. You can see something similar with other attributes: $ declare -i x $ [[ -v x ]] || echo "x not defined" x not defined $ declare -p x declare -i x > > # Empty array declared without parenthesis > unset myArr > declare -a myArr=() > typeset -p myArr > echo "${#myArr[@]}" > > output: > declare -a myArr=() > 0 > > With the assignment, you have an actual parameter named myArr. Continuing the integer attribute example from above, $ x=3 $ declare -p x declare -i x="3" $ [[ -v x ]] || echo "x not defined" # No output -- Clint
read and inconsistent handling of trailing null field?
Configuration Information [Automatically generated, do not change]: Machine: x86_64 OS: darwin19.2.0 Compiler: gcc Compilation CFLAGS: -g -O2 -Wno-parentheses -Wno-format-security uname output: Darwin hemma.local 19.2.0 Darwin Kernel Version 19.2.0: Sat Nov 9 03:47:04 PST 2019; root:xnu-6153.61.1~20/RELEASE_X86_64 x86_64 Machine Type: x86_64-apple-darwin19.2.0 Bash Version: 5.0 Patch Level: 11 Release Status: release Description: read seems to incorrectly drop a null field when performing word-splitting and more fields than variables. All the examples below use IFS== read -r n v for some input of the form ``name=var...`` The relative bit of the POSIX spec concerns how to set the variables when there are fewer arguments to read than there are fields. • The field that corresponds to the last var in the normal assignment sequence described above • The delimiter(s) that follow the field corresponding to the last var • The remaining fields and their delimiters, with trailing IFS white space ignored Repeat-By: % ./bash bash-5.0$ echo $BASH_VERSION 5.0.11(5)-release bash-5.0$ IFS== read -r n v <<< "name=var=" bash-5.0$ echo "$v" var I would expect "var=" as the output, as the string is split into 3 fields (the last being empty). (ksh and dash also drop the final null field, which is what makes me suspect I am missing a subtlety of the POSIX spec. zsh seems to preserve the final =, though I did not dig into which options I have set that might affect the result.) Same result using here-document, so I don't think this is a here-string issue. If the trailing null field is not the one to put the field count over the argument count, it works as expected. bash-5.0$ IFS== read -r n v <<< "name=var=f=" bash-5.0$ echo "$v" var=f= bash-5.0$ IFS== read -r n v <<< "name=var==" bash-5.0$ echo "$value" var==
Re: read and inconsistent handling of trailing null field?
> On 2020 Jan 29 , at 10:30 a, Chet Ramey wrote: > > On 1/29/20 10:19 AM, Clint Hepner wrote: > >> Bash Version: 5.0 >> Patch Level: 11 >> Release Status: release >> >> Description: >> >> read seems to incorrectly drop a null field when performing word-splitting >> and more fields than variables. >> >> All the examples below use >> >>IFS== read -r n v >> >> for some input of the form ``name=var...`` >> >> >> The relative bit of the POSIX spec concerns how to set the variables when >> there are fewer arguments >> to read than there are fields. > > There are exactly two variables and two (split) arguments. > > "The shell shall treat each character of the IFS as a delimiter and use the > delimiters as field terminators to split..." > > https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_05 > > Ah, OK. So if I have IFS=, read -r n v <<< "a,b,c," there are two variables and 3 split arguments: "a", "b", and "c". Then according to the specification for read, "a" is assigned to n, and we assign to v as follows: 1. first add the second field "b": v=b 2. then the delimiter following "b": v=b, 3. The remaining fields and their delimiters: first v=b,c then v=b,c, So the final "," in the value of v isn't separating c and a mythical null field, but is terminating the final field c. Then IFS=, read -r n v <<< "a,b,," has fields "a", "b", and "", and again v is assigned "b", ",", "", ",". Thanks Chet and Greg (for pointing out https://mywiki.wooledge.org/BashPitfalls#pf47) -- Clint
Inconsistent arithmetic evaluation of parameters
Configuration Information [Automatically generated, do not change]: Machine: x86_64 OS: darwin14.5.0 Compiler: clang Compilation CFLAGS: -DPROGRAM='bash' -DCONF_HOSTTYPE='x86_64' -DCONF_OSTYPE='darwin14.5.0' -DCONF_MACHTYPE='x86_64-apple-darwin14.5.0' -DCONF_VENDOR='apple' -DLOCALEDIR='/usr/local/Cellar/bash/4.3.42/share/locale' -DPACKAGE='bash' -DSHELL -DHAVE_CONFIG_H -DMACOSX -I. -I. -I./include -I./lib -I./lib/intl -I/private/tmp/bash20150826-30526-beo5d/bash-4.3/lib/intl -DSSH_SOURCE_BASHRC uname output: Darwin 192.168.1.17 14.5.0 Darwin Kernel Version 14.5.0: Wed Jul 29 02:26:53 PDT 2015; root:xnu-2782.40.9~1/RELEASE_X86_64 x86_64 Machine Type: x86_64-apple-darwin14.5.0 Bash Version: 4.3 Patch Level: 42 Release Status: release Description: Parameter names are recursively evaluated in an arithmetic expression, but this is not done consistently. Repeat-By: foo=bar bar=5 echo $(( foo ))# produces 5 echo $(( foo++ )) # produces 5 echo $foo # produces 6, not bar echo $bar # produces 5, not 6 Fix: It's not clear what should be fixed. First of all, it's not clear what foo is actually evaluating to. If it evaluates to bar, then bar should be incremented. If it evaluates to 5, then the autoincrement should be a syntax error. It seems like the "correct" behavior would be for a parameter to be evaluated until its value is a parameter name whose value is an actual integer, such that foo=bar bar=baz baz=5 echo $(( foo++ )) # produces 5; result should be baz=6 and foo, bar unchanged.
Word-splitting with here document?
Configuration Information [Automatically generated, do not change]: Machine: x86_64 OS: darwin13.4.0 Compiler: clang Compilation CFLAGS: -DPROGRAM='bash' -DCONF_HOSTTYPE='x86_64' -DCONF_OSTYPE='darwin13.4.0' -DCONF_MACHTYPE='x86_64-apple-darwin13.4.0' -DCONF_VENDOR='apple' -DLOCALEDIR='/usr/local/Cellar/bash/4.3.30/share/locale' -DPACKAGE='bash' -DSHELL -DHAVE_CONFIG_H -DMACOSX -I. -I. -I./include -I./lib -I./lib/intl -I/private/tmp/bash-tugB48/bash-4.3/lib/intl -DSSH_SOURCE_BASHRC uname output: Darwin patikoija 14.4.0 Darwin Kernel Version 14.4.0: Thu May 28 11:35:04 PDT 2015; root:xnu-2782.30.5~1/RELEASE_X86_64 x86_64 Machine Type: x86_64-apple-darwin13.4.0 Bash Version: 4.3 Patch Level: 30 Release Status: release Description: Unexpected word splitting in here string. According to the man page, "Pathname expansion and word splitting are not performed." This is essentially the same wording used to explain how `[[...]]` treats its contents, but the here string seems to behave differently. Repeat-By: $ x="foobar" $ [[ $x == "foobar" ]] # succeeds, no word splitting on value of x $ cat <<< $x # Word-splitting appears to collapse the run of whitespace foo bar $ cat <<< "$x" # Whitespace preserved, as with here doc foo bar
Execution of code by ${...@P}
Configuration Information [Automatically generated, do not change]: Machine: x86_64 OS: darwin16.0.0 Compiler: clang Compilation CFLAGS: -DPROGRAM='bash' -DCONF_HOSTTYPE='x86_64' -DCONF_OSTYPE='darwin16.0.0' -DCONF_MACHTYPE='x86_64-apple-darwin16.0.0' -DCONF_VENDOR='apple' -DLOCALEDIR='/usr/local/Cellar/bash/4.4_1/share/locale' -DPACKAGE='bash' -DSHELL -DHAVE_CONFIG_H -DMACOSX -I. -I. -I./include -I./lib -I./lib/intl -I/private/tmp/bash-20160928-76620-1cvsdye/bash-4.4/lib/intl -DSSH_SOURCE_BASHRC -Wno-parentheses -Wno-format-security uname output: Darwin 192.168.1.21 16.1.0 Darwin Kernel Version 16.1.0: Thu Oct 13 21:26:57 PDT 2016; root:xnu-3789.21.3~60/RELEASE_X86_64 x86_64 Machine Type: x86_64-apple-darwin16.0.0 Bash Version: 4.4 Patch Level: 0 Release Status: release Description: ${...@P} expansion allows arbitrary code to run. This might be intentional, as it is how prompt strings work, but it does feel like an understated security risk. Repeat-By: $ foo='$(echo hello)' $ echo "${foo}" $(echo hello) $ echo "${foo@P}" hello Fix: The man page might explicitly state that command substitutions in the value of the expanded parameter will be executed. This also suggests one or more additional operators that perform things like parameter expansion, pathname expansions, etc.