Re: select syntax violates the POLA
Date:Wed, 07 Apr 2021 22:24:27 -0400 From:wor...@alum.mit.edu (Dale R. Worley) Message-ID: <87a6q9ikdg@hobgoblin.ariadne.com> | "The documentation is the contract between the user and | the implementer." If something undocumented happens to work, there is | no requirement on the implementer to maintain its functionality. That might, or might not, be true - in both directions (implementors are often constrained to keep old things, that were never documented, working, because they became known, and are used - similarly some things were once documented, but are no longer, as a better solution was implemented - but the old undocumented code has to stay, essentially forever, for the benefit of those who used it when it was documented). But whatever all that ends up meaning, if anything significant here, it certainly does not mean that the implementation is required to reject extensions that are not documented. Or that it is any kind of bug for it not to do so. As long as you stick to using the implementation as documented (you keep up your end of the "contract"), you will never observe this happening. But when someone else does not, and asks about something that looks like it is using undocumented behaviour, it might be OK to suggest to them that what they're doing is unsafe - but not to suggest that the implementation should reject what they are doing. That is ' "{" should not be recognized as a reserved word in this situation. ' is simply wrong. The situation mentioned was "else {", which actually is documented as working, but never mind. kre
Re: select syntax violates the POLA
Robert Elz writes: > You're assuming that the manual is a precise specification of what > is allowed. Um, of course. "The documentation is the contract between the user and the implementer." If something undocumented happens to work, there is no requirement on the implementer to maintain its functionality. Dale
Re: select syntax violates the POLA
On 4/5/2021 14:21, Chet Ramey wrote: This presented an opportunity to marginally simplify the grammar, so it's a win all around. The change will be in the next devel branch push. You have my sincere gratitude. I did not expect so much to come of it. Chet --*greywolf;
Re: select syntax violates the POLA
On 4/5/2021 13:52, Chet Ramey wrote: On 4/1/21 5:40 PM, Greywolf wrote: Or do you mean my coding style (which has been valid for over 25 years)? Hey, if you want to go there, `select' has been in bash with its current syntax for longer than that. ;-) (A month over 27 years, if you're curious.) HAH! And I only just found about it very recently while perusing the man page! Go figure! In any case, I apologise if, at any point, I came across as hostile (never my intent), and I thank you for taking the time to parley. I've learned a few things. --*greywolf;
Re: select syntax violates the POLA
On 4/1/21 5:54 PM, Greywolf wrote: On 4/1/2021 8:57, Chet Ramey wrote: It's more like `select' doesn't inherit some of the shell's special cases. select dir in ${d[@]}; do { break; } done; ...but select breaks on the "} done;" syntax Yes, you need a list terminator so that `done' is recognized as a reserved word here. `;' is sufficient. Select doesn't allow the `done' unless it's in a command position. Some of the other compound commands have special cases, mostly inherited from the Bourne shell, to allow it. I took a look at bash-1.14, where the `select' command first appeared. At the time, it was identical to the `for' command -- which makes sense, since the syntaxes are essentially identical (and internally, they are represented the same way). They both used the `list' grammar production. When I updated the grammar to use the `compound_list' production in bash-2.0, to be closer to how POSIX specified the compound commands in the POSIX grammar, I left the select command alone. It's been the same way since late 1994, though bash-2.0 wasn't released until 1996. I took this opportunity to examine the grammar again, and there's no good reason `select' and `for' should be different -- they started out the same, and they should both use compound_list now. So they will. This presented an opportunity to marginally simplify the grammar, so it's a win all around. The change will be in the next devel branch push. Chet -- ``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: select syntax violates the POLA
On 4/1/21 9:23 PM, Dale R. Worley wrote: Greg Wooledge writes: It's amazing how many people manage to post their code with NO comments or explanations of what it's supposed to do, what assumptions are being made about the inputs, etc. This leaves us to guess. It seems to be a modern style. When I was learning to program, poorly commented code was considered a failing. But recently, I have had managers object that I put too many comments in. If it was hard to write, it should be hard to understand! (That's snark, for those who are wondering.) -- ``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: select syntax violates the POLA
On 4/1/21 5:40 PM, Greywolf wrote: Or do you mean my coding style (which has been valid for over 25 years)? Hey, if you want to go there, `select' has been in bash with its current syntax for longer than that. ;-) (A month over 27 years, if you're curious.) -- ``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: select syntax violates the POLA
On 4/5/2021 6:27, Chet Ramey wrote: On 4/5/21 5:06 AM, Greywolf wrote: but if you want to go down that track, it's kind of interesting to note that {} on a single line demands a ; before the }, while () prohibits it. This isn't true: $ ./bash -c '(echo a b c;)' a b c but it is the case that } is a reserved word, while ) is an operator. D'OH! You're right! I was thinking $ foo &; Can't put a semicolon after a null statement. My mistake. Carry on... --*greywolf;
Re: select syntax violates the POLA
On 4/5/21 5:06 AM, Greywolf wrote: the same level of egregious brokenness as select. Good god, take a breath. -- ``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: select syntax violates the POLA
On 4/5/21 5:06 AM, Greywolf wrote: but if you want to go down that track, it's kind of interesting to note that {} on a single line demands a ; before the }, while () prohibits it. This isn't true: $ ./bash -c '(echo a b c;)' a b c but it is the case that } is a reserved word, while ) is an operator. -- ``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: select syntax violates the POLA
On 4/2/2021 8:21, konsolebox wrote: That's not a rule but a special compromise. [[ ]] and (( )) are a form of reserved words themselves just like () and {} as they can be used multi-line but they aren't allowed to be adjacent to else et al without a semicolon. [[ ]], (( )), {}, and () are practically just commands with first-class parsing that consistently have to end with a semicolon if followed by another reserved word or command. I'd call it less a compromise than a mechanism; of all listed, {} represents a block of code in the current shell, () represents a block of code in a subshell... but if you want to go down that track, it's kind of interesting to note that {} on a single line demands a ; before the }, while () prohibits it. This also seems inconsistent to me, but not at the same level of egregious brokenness as select. --*greywolf;
Re: select syntax violates the POLA
On 4/1/2021 8:57, Chet Ramey wrote: Yes, you need a list terminator so that `done' is recognized as a reserved word here. `;' is sufficient. Select doesn't allow the `done' unless it's in a command position. Some of the other compound commands have special cases, mostly inherited from the Bourne shell, to allow it. I don't know that I'd call them "special cases" if sh has pretty much condoned it from the get-go; 'select' is the outlier, from my POV. --*greywolf;
Re: select syntax violates the POLA
On 4/4/2021 23:13, konsolebox wrote: On Sat, Apr 3, 2021 at 1:09 AM Robert Elz wrote: | [[ ]] and (( )) are a form of reserved words themselves Those are bash specials, and I am fairly sure that (( and )) will be operators, not reserved words (they cannot really be the latter, as ( and ) are operators) and I suspect that [[ and ]] might be as well, but there I'm not sure. operators and reserved words are quite different things. Operators (unquoted) are recognised as themselves wherever they appear. Stop suspecting and read the source code. Look at parse.y starting at line 2150. They are labeled as "Reserved words". [[ and ]] behave like reserved words requiring whitespace between themselves and their operands. (( and )) do not carry that restriction; within (( )), neither do any of */%^&|+- (or their respective OP=), nor == || && !. This effectively classifies (( )) as operators. But we've drifted considerably afield. --*greywolf;
Re: select syntax violates the POLA
5 Nisan 2021 Pazartesi tarihinde konsolebox yazdı: > > The manual itself may be lacking in some places but the syntax here is > explicit. There's no reason to follow otherwise. These "other methods" > can only be an implementation mistake or a compromise that's not > exactly a supported functionality or feature. This case where () and > {} are allowed to not end with semicolon before 'else' when others > aren't is likely one. These all work (as expected) on the development branch: bash-5.1$ if : ; then case _ in esac else : ; fi bash-5.1$ if : ; then for _ do : ; done else : ; fi bash-5.1$ if : ; then [[ _ ]] else : ; fi bash-5.1$ if : ; then (( 0 )) else : ; fi bash-5.1$ if { : ; } then while { : ; } do break ; done else : ; fi bash-5.1$ If they didn't that'd be a defect in the shell, POSIX allows these constructs, and it also makes sense that a list separator is optional between else and the preceding command when that command is terminated with a reserved word. > > and the ';' there is just an > > indication that something must ensure that the word that follows is > > correctly interpreted as a reserved word (when one is required). > > Then why does it not work with other keywords that begin a block? It does work with then, do, elif, else, done, esac, and }. -- Oğuz
Re: select syntax violates the POLA
On Sat, Apr 3, 2021 at 1:09 AM Robert Elz wrote: > | [[ ]] and (( )) are a form of reserved words themselves > > Those are bash specials, and I am fairly sure that (( and )) will be > operators, not reserved words (they cannot really be the latter, as ( and > ) are operators) and I suspect that [[ and ]] might be as well, but there > I'm not sure. operators and reserved words are quite different things. > Operators (unquoted) are recognised as themselves wherever they appear. Stop suspecting and read the source code. Look at parse.y starting at line 2150. They are labeled as "Reserved words". -- konsolebox
Re: select syntax violates the POLA
On Mon, Apr 5, 2021 at 12:46 PM Robert Elz wrote: > > Date:Sun, 04 Apr 2021 20:27:15 -0400 > From:wor...@alum.mit.edu (Dale R. Worley) > Message-ID: <87wntha84c@hobgoblin.ariadne.com> > > > | The manual page says > | > |if list; then list; [ elif list; then list; ] ... [ else list; ] fi > | > | so clearly there should be a ; or newline before the list in the > | else-clause. > > You're assuming that the manual is a precise specification of what > is allowed. It isn't. At least in this case it shows something that > works, so if you write an if statement that way, it will function. > That does not imply that there are not other methods. The manual itself may be lacking in some places but the syntax here is explicit. There's no reason to follow otherwise. These "other methods" can only be an implementation mistake or a compromise that's not exactly a supported functionality or feature. This case where () and {} are allowed to not end with semicolon before 'else' when others aren't is likely one. > and the ';' there is just an > indication that something must ensure that the word that follows is > correctly interpreted as a reserved word (when one is required). Then why does it not work with other keywords that begin a block? The enclosure of {} and () should make semicolons optional for parsing with them as well. This should have been explicitly allowed by the shell. It's highly doable even if they are followed with non-keywords. Just look at awk's syntax. -- konsolebox
Re: select syntax violates the POLA
Date:Sun, 04 Apr 2021 20:27:15 -0400 From:wor...@alum.mit.edu (Dale R. Worley) Message-ID: <87wntha84c@hobgoblin.ariadne.com> | The manual page says | |if list; then list; [ elif list; then list; ] ... [ else list; ] fi | | so clearly there should be a ; or newline before the list in the | else-clause. You're assuming that the manual is a precise specification of what is allowed. It isn't. At least in this case it shows something that works, so if you write an if statement that way, it will function. That does not imply that there are not other methods. In general, when reading the bash man page, anywhere it says "list;" (except apparently in select statements) you should read that as meaning the same as the POSIX compound_list, and the ';' there is just an indication that something must ensure that the word that follows is correctly interpreted as a reserved word (when one is required). A ';' will do that. So do other things. kre ps: you can also use '&' in place of ';' or newline, when a separator is required. Though that gives the preceding command a different operational behaviour of course.
Re: select syntax violates the POLA
Robert Elz writes: > From:wor...@alum.mit.edu (Dale R. Worley) > > | I was going to ask why "else {" works, > > The right question would be why '} else' works. Yeah, typo on my part. The manual page says if list; then list; [ elif list; then list; ] ... [ else list; ] fi so clearly there should be a ; or newline before the list in the else-clause. But the grammar doesn't seem to enforce that: if_clause : If compound_list Then compound_list else_part Fi I'm sure that the real answer involves decrypting the logic inside Bash that turns on recognition of reserved words, and that must be more complicated than the rule in the manual page. Dale
Re: select syntax violates the POLA
On Thu, Apr 1, 2021 at 7:59 PM Robert Elz wrote: > Alternatively > d=( $( ls -d /usr/src/pkg/*/$1 ) ) > or just > d=( $( printf %s\\n /usr/src/pkg/*/$1 ) ) > > Just to be sure.Personally I'd do > > set -- /usr/src/pkg/*/$1 > Just the glob is fine in the array assignment, it splits and globs the same as in arguments to 'set': d=( /usr/src/pkg/*/$1 ) (If there was any context that splits but doesn't glob, this isn't one)
Re: select syntax violates the POLA
On Fri, Apr 2, 2021 at 2:04 AM Robert Elz wrote: > chet.ra...@case.edu said: > | Yes, you need a list terminator so that `done' is recognized as a > reserved > | word here. `;' is sufficient. Select doesn't allow the `done' unless > it's > | in a command position. > > isn't really all that appealing as an explanation. select isn't part > of the standard, so its syntax is arbitrary, which means that nothing can > really be considered wrong, but while we often think of reserved words > (not counting the special cases in case and for statements) as only working > in the command word position, that's not how it really is. They work > there, > they also should work following other reserved words (most of them, but > '}' is not one of the exceptions). so '} done' should work correctly, > always, if the '}' is a reserved word, and a ';' or newline between them > should not be needed. > FWIW, it works in the other shells I know that support select: $ cat select.sh select x in foo bar; do { echo $x; break; } done; $ for sh in bash ksh mksh zsh; do echo "== $sh"; $sh select.sh <<< 1; done == bash select.sh: line 5: syntax error near unexpected token ‘done’ select.sh: line 5: `} done;' == ksh 1) foo 2) bar foo == mksh 1) foo 2) bar #? foo == zsh 1) foo 2) bar ?# foo
Re: select syntax violates the POLA
Date:Fri, 02 Apr 2021 09:02:40 +0200 From:Andreas Schwab Message-ID: <87o8exp3sf@linux-m68k.org> | The two case are not really different, they are covered by the same | rule: Yes, I knew that ... but they are different, as in the "else {" case the '{' is in the command word position (which "else" is not in "} else") and so is a reserved word for that reason as well. Everyone (well, everyone who understands something about shell syntax) knows the "reserved words happen in the command word position" rule, it is what makes echo if I do it while the case is ! done then in payment for ... work without there being anything which is a reserved word there, but (as is obvious by some of this discussion) not everyone realises the consecutive reserved words rule exists. kre
Re: select syntax violates the POLA
Date:Fri, 2 Apr 2021 23:06:40 +0800 From:konsolebox Message-ID: | > The right question would be why '} else' works. | | This inconsistency should be fixed and prevent people from | using it wrong. `}; else` should work Yes. | but not `} else` No, that should work too. The "then" part of an if statement (which is what the '}' is the last element of in that example, obviously, takes a list if_clause : If compound_list Then compound_list else_part Fi and the list (compound_list in posix speak) can be compound_list : linebreak term where linebreak is an optional newline (but is before the term anyway so isn't relevant here as we're looking at the ending, not the beginning) and term can be term : and_or and and-or can be and_or : pipeline and pipeline can be pipeline : pipe_sequence and pipe_sequence can be pipe_sequence : command and command can be command : compound_command and compound_command can be compound_command : brace_group and brace_group is brace_group : Lbrace compound_list Rbrace ; Observe that following that sequence, there is no separator (';' etc) required between the Rbrace ('}') that terminates the brace_group which is the compound_command which is the command which is the pipe_sequence which is the pipeline which is the and_or which is the term which is the last thing in the compound_list after which "else" follows immediately. Of course, all the "can be" rules above have alternatives, other things are possible, in particular, the full rule for compound_list is compound_list : linebreak term | linebreak term separator ; so it is obvious (very obvious) that a separator is allowed after the term, but not required. | just like how `{ :; } :` doesn't. That is an entirely different thing. ':' isn't a reserved word, so the reserved word rule isn't relevant, and sequential commands (like the group, and the second ':' in that example) need to be separated by some kind of separator (';' '&' or newline). And from your other message: | That's not a rule but a special compromise. No, it is a rule, it is required to allow the 'else' in the example above to be a reserved word, otherwise it would just be a normal word, and that would be a syntax error. | [[ ]] and (( )) are a form of reserved words themselves Those are bash specials, and I am fairly sure that (( and )) will be operators, not reserved words (they cannot really be the latter, as ( and ) are operators) and I suspect that [[ and ]] might be as well, but there I'm not sure. operators and reserved words are quite different things. Operators (unquoted) are recognised as themselves wherever they appear. | just like () and {} '(' and ')' are operators. '{' and '}' are reserved words. | as they can be used multi-line but That has nothing to do with anything. Anywhere where the grammar allows linebreak or separator (maybe more) can be used multi-line. Anwhere those things are not in the grammar, line breaks (not counting \newline or quoted newlines) are not permitted. | but they aren't allowed to be adjacent to else et al without a semicolon. Nonsense. | practically just commands with first-class parsing that consistently | have to end with a semicolon No, they don't (even if you extend semicolon to include ampersand and newline). | if followed by another reserved word or command if followed by another command yes, as the separator is just that, a separator, it separates different commands, it is not a terminator (unlike the ';' in C expression statements for example). Where reserved words are allowed entirely depends upon what the grammar allows. And as above, "} else {" is a perfectly valid sequence as part of an "if" statement. kre
Re: select syntax violates the POLA
On Fri, Apr 2, 2021 at 3:03 PM Andreas Schwab wrote: > > On Apr 02 2021, Robert Elz wrote: > > > Date:Thu, 01 Apr 2021 21:33:31 -0400 > > From:wor...@alum.mit.edu (Dale R. Worley) > > Message-ID: <874kgpqxlg@hobgoblin.ariadne.com> > > > > | I was going to ask why "else {" works, > > > > Wrong question. That one is easy. What follows > > 'else' is a list and the simplest form of a list > > is a simple command, which starts with a command > > word, so reserved words are always going to work > > there, even without the "follows a reserved word' > > rule. > > > > The right question would be why '} else' works. > > The two case are not really different, they are covered by the same > rule: > > This recognition shall only occur when none of the characters is > quoted and when the word is used as: > > * The first word following one of the reserved words other than > case, for, or in > That's not a rule but a special compromise. [[ ]] and (( )) are a form of reserved words themselves just like () and {} as they can be used multi-line but they aren't allowed to be adjacent to else et al without a semicolon. [[ ]], (( )), {}, and () are practically just commands with first-class parsing that consistently have to end with a semicolon if followed by another reserved word or command. -- konsolebox
Re: select syntax violates the POLA
On Fri, Apr 2, 2021 at 11:41 AM Robert Elz wrote: > > Date:Thu, 01 Apr 2021 21:33:31 -0400 > From:wor...@alum.mit.edu (Dale R. Worley) > Message-ID: <874kgpqxlg@hobgoblin.ariadne.com> > > | I was going to ask why "else {" works, > > Wrong question. That one is easy. What follows > 'else' is a list and the simplest form of a list > is a simple command, which starts with a command > word, so reserved words are always going to work > there, even without the "follows a reserved word' > rule. > > The right question would be why '} else' works. Indeed. This inconsistency should be fixed and prevent people from using it wrong. `}; else` should work but not `} else` just like how `{ :; } :` doesn't. -- konsolebox
Re: select syntax violates the POLA
On Apr 02 2021, Robert Elz wrote: > Date:Thu, 01 Apr 2021 21:33:31 -0400 > From:wor...@alum.mit.edu (Dale R. Worley) > Message-ID: <874kgpqxlg@hobgoblin.ariadne.com> > > | I was going to ask why "else {" works, > > Wrong question. That one is easy. What follows > 'else' is a list and the simplest form of a list > is a simple command, which starts with a command > word, so reserved words are always going to work > there, even without the "follows a reserved word' > rule. > > The right question would be why '} else' works. The two case are not really different, they are covered by the same rule: This recognition shall only occur when none of the characters is quoted and when the word is used as: * The first word following one of the reserved words other than case, for, or in Andreas. -- Andreas Schwab, sch...@linux-m68k.org GPG Key fingerprint = 7578 EB47 D4E5 4D69 2510 2552 DF73 E780 A9DA AEC1 "And now for something completely different."
Re: select syntax violates the POLA
Date:Thu, 01 Apr 2021 21:33:31 -0400 From:wor...@alum.mit.edu (Dale R. Worley) Message-ID: <874kgpqxlg@hobgoblin.ariadne.com> | I was going to ask why "else {" works, Wrong question. That one is easy. What follows 'else' is a list and the simplest form of a list is a simple command, which starts with a command word, so reserved words are always going to work there, even without the "follows a reserved word' rule. The right question would be why '} else' works. kre
Re: select syntax violates the POLA
On 4/1/2021 16:03, Robert Elz wrote: Partly because if you didn't use the braces, the issue wouldn't have arisen. (And because to most of us it just looks weird, kind of like people who write functions like f() {( commands to run in a subshell )} where the braces do nothing useful at all. and should just be omitted. Heh. Nope -- if it's to be subshelled, I do not use the braces around the parens. that's not an unreasonable use explanation. I find that a consistent style and correct indentation work well enough for this though. I have a consistent style and indentation ("correct" is subjective) :) ... so '} done' should work correctly, always, if the '}' is a reserved word, and a ';' or newline between them should not be needed. Which was why I was kind of taken aback when it failed. kre Thank you, again! --*greywolf;
Re: select syntax violates the POLA
Chet Ramey writes: > Yes, you need a list terminator so that `done' is recognized as a reserved > word here. `;' is sufficient. Select doesn't allow the `done' unless it's > in a command position. Some of the other compound commands have special > cases, mostly inherited from the Bourne shell, to allow it. I was going to ask why "else {" works, since according to the manual page, "{" should not be recognized as a reserved word in this situation. Dale
Re: select syntax violates the POLA
Greg Wooledge writes: > It's amazing how many people manage to post their code with NO comments > or explanations of what it's supposed to do, what assumptions are being > made about the inputs, etc. This leaves us to guess. It seems to be a modern style. When I was learning to program, poorly commented code was considered a failing. But recently, I have had managers object that I put too many comments in. Dale
Re: select syntax violates the POLA
Date:Thu, 1 Apr 2021 14:40:13 -0700 From:Greywolf Message-ID: <354ec4df-c24e-d82a-32ad-788a352a5...@starwolf.com> | Or do you mean my coding style It was that, | (which has been valid for over 25 years)? | (why's everyone bagging on my style and ignoring my original point, the | outlying brokenness, anyway?) Partly because if you didn't use the braces, the issue wouldn't have arisen. (And because to most of us it just looks weird, kind of like people who write functions like f() {( commands to run in a subshell )} where the braces do nothing useful at all. and should just be omitted. But | I started using the curly braces because every (worthwhile) editor has a | paren-match function that's not an unreasonable use explanation. I find that a consistent style and correct indentation work well enough for this though. | I just thought I'd try out select and was astonished when | | select x in ${list}; do { | break; | } done; | | was the only one that failed. Yes, and on second thoughts, the: chet.ra...@case.edu said: | Yes, you need a list terminator so that `done' is recognized as a reserved | word here. `;' is sufficient. Select doesn't allow the `done' unless it's | in a command position. isn't really all that appealing as an explanation. select isn't part of the standard, so its syntax is arbitrary, which means that nothing can really be considered wrong, but while we often think of reserved words (not counting the special cases in case and for statements) as only working in the command word position, that's not how it really is. They work there, they also should work following other reserved words (most of them, but '}' is not one of the exceptions). so '} done' should work correctly, always, if the '}' is a reserved word, and a ';' or newline between them should not be needed. kre
Re: select syntax violates the POLA
On Thu, Apr 01, 2021 at 02:54:55PM -0700, Greywolf wrote: > the requirement > to have ${var[ix]} instead of honouring $var[ix] with regard to arrays > is another one). Before the introduction of arrays, $var[ix] already had a meaning: the value of the "var" parameter, followed by the 4-character string [ix]. Redefining $var[ix] to mean the same thing as ${var[ix]} would have broken existing scripts.
Re: select syntax violates the POLA
Hi, Chet! I've read a lot of your posts long ago, as well! On 4/1/2021 8:57, Chet Ramey wrote: It's more like `select' doesn't inherit some of the shell's special cases. select dir in ${d[@]}; do { break; } done; >> ...but select breaks on the "} done;" syntax Yes, you need a list terminator so that `done' is recognized as a reserved word here. `;' is sufficient. Select doesn't allow the `done' unless it's in a command position. Some of the other compound commands have special cases, mostly inherited from the Bourne shell, to allow it. Firstly, thank you for your concise reply. I discovered that making it '}; done;' as you suggested here worked, shortly after my broken astonishment :). kre mentioned that it's a ksh holdover. This explains a great many things considering how horribly broken I have found ksh to be (and the weak arguments supporting that brokenness; among them, the need to say 'fg %4' instead of merely being able to say '%4'; the requirement to have ${var[ix]} instead of honouring $var[ix] with regard to arrays is another one). Lastly, thanks for not bagging on my coding style. It was somewhat intentional, somewhat accidental when I started using it 25 years back. Being able to paren-match my for-in-do-done, while/until-do-done, if-elif-else-fi has been a timesaver. It not only helps me spot missing closures, it helps me spot missing quotes. [I think the only thing I wish would be enhanced and accepted further was for it to work with case-esac, but that hasn't changed in 25 years, either, and it's minor, so I'm not holding my breath. :) ] Cheers, --*greywolf;
Re: select syntax violates the POLA
On 4/1/2021 9:58, Robert Elz wrote: Date:Thu, 1 Apr 2021 11:36:14 -0400 From:Greg Wooledge Message-ID: | On Thu, Apr 01, 2021 at 01:36:59AM -0700, greyw...@starwolf.com wrote: | > The following is valid shell code: | > | > d=($(ls /usr/src/pkg/*/$1)); | | Syntactically valid, but semantically wrong Mr. Elz! Long time! I remember reading your posts 30 years ago! [ much other ado elided ] | "${d[@]}" with quotes. Again, yes, but in practice here, not needed. | What purpose do the extra curly braces serve? Good question, wondered that myself. Note that if they were omitted the odd syntax issue wouldn't have arisen, as the done would follow "break;" and be recognised. Unfortunately the way bash has implemented arrays, $d[@] doesn't do The Right Thing. Or do you mean my coding style (which has been valid for over 25 years)? (why's everyone bagging on my style and ignoring my original point, the outlying brokenness, anyway?) I started using the curly braces because every (worthwhile) editor has a paren-match function which shows you the matching brace at the other end, and I was tired of searching for which conditional component (while, if, for, and so on) was missing its closing word. This helps me immensely. After all that, and ignoring select's syntax (it was invented by ksh, long long ago, and isn't going to change) it is a dumb interface that can always be coded better using other mechanisms. And when you do that you can allow for much more flexible input than just the line number the select demands. Indeed, I have written such animals from scratch; I just thought I'd try out select and was astonished when select x in ${list}; do { break; } done; was the only one that failed. If you avoid select, and avoid arrays, then any Bourne style shell will work. So, do that. I will also note that the arrays don't give me grief in the least. :) kre Thank you so much for your response! You got exactly what I was after! --*greywolf;
Re: select syntax violates the POLA
On 4/1/2021 9:16, konsolebox wrote: On Thu, Apr 1, 2021 at 11:25 PM wrote: if ((n > 1)); then { echo "Ambiguous dir specification"; exit 1; } else { dir=${d[0]}; } fi; The grouping is unnecessary or should be separate from the first class syntax. Bash is not C or Go and shouldn't be written like it. I didn't ask for your opinion on my coding style. It's worked correctly for 25 years. I have my reasons.
Re: select syntax violates the POLA
Date:Thu, 1 Apr 2021 13:18:07 -0400 From:Greg Wooledge Message-ID: | It's amazing how many people manage to post their code with NO comments | or explanations of what it's supposed to do, what assumptions are being | made about the inputs, etc. This leaves us to guess. Agreed, it is a problem in general. It just happens that in this case I can see exactly what is intended (as I know the environment) so I don't need to guess. | I'm guessing that /usr/src/pkg/*/* is a list of files, not a list of | directories. You're guessing that it's a list of directories. No, I know it is a list of directories. No guessing involved. | In the original code, if it's a list of directories, then we have | "ls firstdir seconddir" which expands to a list of mangled filenames Yes, the original was broken. But that was not what the message was about, it was about the syntax of select. That the rest of the example code wouldn't have worked was kind of not the point, he wasn't asking for assistance with that. What he wanted to know was why his usage of select was giving a syntax error. Chet answered that. | Now, this is obviously just a guess, and I could be extremely wrong | about it. For one thing, they used the variable name "d". That seems | to indicate that it should be a list of directories, rather than a list | of files. More than that, after one of them is selected ("select dir ...") the code did "cd $dir" (you even commented on the lack of quotes in that statement) - so a directory name is clearly what is wanted. Even if you didn't know the environment, this makes that very clear. | So, perhaps their code is simply *broken*, and where they *thought* they | would be getting a list of directories, they actually get a list of | mangled useless filenames, because they forgot the -d argument to ls. Yes. | | > | d=(/usr/src/pkg/*/"$1") | > | > definitely not that, the quotes are wrong in any case | | They are not! They are. As I said, when used $1 is likely to be a pattern 'p5-*' or similar, and it wants to locate all directories named starting with p5- not the one (non-existing) directory named literally "p5-*". | > Alternatively | > d=( $( ls -d /usr/src/pkg/*/$1 ) ) | | This needs quotes around "$1" Again, no it doesn't. Quote everything is a nice starting point, but it does not universally apply. Filename expansion of the $1 is definitely wanted here. | but yes, it's quite possible that this was | their intent. Of course, this is still *broken*, but it only breaks if | one of the directory names contains whitespace characters. They don't. They never will. Of course it could break if IFS was set to something unusual, but since this script is (I presume) not doing that, that's also not an issue. | It's likely | that they didn't happen to have any such directories in their test | environment, and therefore, this bug would go unnoticed for a long time. It would never be noticed, as there will never be a category (the '*') or package (the $1) name containing a space or any other meta-char. There are rules for the names. Too much of pkgsrc (which is what this is dealing with, the NetBSD packaging system, also available for lots of other systems, including various linux variants, Solaris, OSX, and more) depends on the names having specific characteristics for this to ever be changed. | > or just | > d=( $( printf %s\\n /usr/src/pkg/*/$1 ) ) | | This is not much better. It still breaks on whitespace. It would. There is none. | If a list of directories (not their contents) is the desired outcome, | then my original code is perfectly fine: | | d=(/usr/src/pkg/*/"$1") | | This will expand to something like | | d=(/usr/src/pkg/vendor1/netcat /usr/src/pkg/vendor2/netcat) Except that it can't.There can be only one "netcat" in all of the category directories, because those things aren't used (or not really used) for the compiled binary packages. If you restrict the $1 to being a literal string (by quoting it) then there could never be more than one name returned, so using an array, and using select to choose the actual one which is wanted, would be a waste of coding effort. I'm not blaming you for not knowing all this, but like I said, I know the environment, and I can see exactly what is being attempted. | > Just to be sure.Personally I'd do | > | > set -- /usr/src/pkg/*/$1 | > | > and then simply use the positional parameters. | | This still needs quotes around "$1", No, it doesn't. | and it's basically the same as the array assignment -- just less flexible, | and more suited to sh than bash. Exactly. It will work with any shell, bash doesn't need to be available. | > Yes. But it turns out not to matter in this case, as none of | > the names will ever contain anything but "normal" characters | > (no spaces, newlines,
Re: select syntax violates the POLA
On 4/1/21 1:18 PM, Greg Wooledge wrote: > On Thu, Apr 01, 2021 at 11:58:13PM +0700, Robert Elz wrote: >> >> | If $1 is not a directory, then you want: >> >> It is a directory, or I'd guess, quite likely a pattern chosen > > It's amazing how many people manage to post their code with NO comments > or explanations of what it's supposed to do, what assumptions are being > made about the inputs, etc. This leaves us to guess. > > I'm guessing that /usr/src/pkg/*/* is a list of files, not a list of > directories. You're guessing that it's a list of directories. > > In the original code, if it's a list of directories, then we have > "ls firstdir seconddir" which expands to a list of mangled filenames > without directory components. And since there's more than one directory, > the array ends up looking like: > > d=(README foo.c foo.h foo README bar.c bar.h foo.c foo.h foobar) > > with repeated filenames, and no knowledge of which filename came out of > which subdirectory. > > I was assuming that this was *not* how it was intended to work, and thus, > I made the guess that /usr/src/pkg/*/$1 expanded to a list of *files*, > and therefore generated a list of full pathnames, e.g. > > d=(/usr/src/pkg/applesauce/Makefile.PL /usr/src/pkg/bananabread/Makefile.PL) > > and then the user can make a meaningful selection from such a list. > > Now, this is obviously just a guess, and I could be extremely wrong > about it. For one thing, they used the variable name "d". That seems > to indicate that it should be a list of directories, rather than a list > of files. > > So, perhaps their code is simply *broken*, and where they *thought* they > would be getting a list of directories, they actually get a list of > mangled useless filenames, because they forgot the -d argument to ls. > >> | d=(/usr/src/pkg/*/"$1") >> >> definitely not that, the quotes are wrong in any case > > They are not! The quotes are wrong, *iff* the intent is that people should be allowed to pass quoted globs as $1 and let those be expanded to produce d=() Which, I can see where Robert is coming from in assuming this. >> (but apart from >> that, if filename expansion happens in array assignments (it doesn't in >> normal ones, and I dislike arrays, so ...) then without the quotes that >> might work. >> >> Alternatively >> d=( $( ls -d /usr/src/pkg/*/$1 ) ) > > This needs quotes around "$1" but yes, it's quite possible that this was > their intent. Of course, this is still *broken*, but it only breaks if > one of the directory names contains whitespace characters. It's likely > that they didn't happen to have any such directories in their test > environment, and therefore, this bug would go unnoticed for a long time. > >> or just >> d=( $( printf %s\\n /usr/src/pkg/*/$1 ) ) > > This is not much better. It still breaks on whitespace. > > If a list of directories (not their contents) is the desired outcome, > then my original code is perfectly fine: > > d=(/usr/src/pkg/*/"$1") > > This will expand to something like > > d=(/usr/src/pkg/vendor1/netcat /usr/src/pkg/vendor2/netcat) > >> Just to be sure.Personally I'd do >> >> set -- /usr/src/pkg/*/$1 >> >> and then simply use the positional parameters. > > This still needs quotes around "$1", and it's basically the same as > the array assignment -- just less flexible, and more suited to sh than > bash. But certainly, this is viable in many cases. > >> Yes. But it turns out not to matter in this case, as none of >> the names will ever contain anything but "normal" characters >> (no spaces, newlines, asterisks, ...) > > Famous Last Words™ It's not too much of a leap if the names are required to be NetBSD ports tree names of packages, which presumably ban such characters and enforce that ban in their tooling. It's not something one would be wise to get into the habit of doing elsewhere, and the quotes don't hurt, so why not add them... unless, again, we assume the intent of the script is in fact to pass in globs. These "Famous Last Words™" are really just a fancy way to repeat your initial, valid objection that the OP gave zero comments or explanation and therefore you're left to guess at the intention without having any contextual knowledge about what /usr/src/pkg is or why one would want to cd into any of them and run make. I suspect Robert does know quite a bit about it though. :) -- Eli Schwartz Arch Linux Bug Wrangler and Trusted User OpenPGP_signature Description: OpenPGP digital signature
Re: select syntax violates the POLA
On Thu, Apr 01, 2021 at 11:58:13PM +0700, Robert Elz wrote: > > | If $1 is not a directory, then you want: > > It is a directory, or I'd guess, quite likely a pattern chosen It's amazing how many people manage to post their code with NO comments or explanations of what it's supposed to do, what assumptions are being made about the inputs, etc. This leaves us to guess. I'm guessing that /usr/src/pkg/*/* is a list of files, not a list of directories. You're guessing that it's a list of directories. In the original code, if it's a list of directories, then we have "ls firstdir seconddir" which expands to a list of mangled filenames without directory components. And since there's more than one directory, the array ends up looking like: d=(README foo.c foo.h foo README bar.c bar.h foo.c foo.h foobar) with repeated filenames, and no knowledge of which filename came out of which subdirectory. I was assuming that this was *not* how it was intended to work, and thus, I made the guess that /usr/src/pkg/*/$1 expanded to a list of *files*, and therefore generated a list of full pathnames, e.g. d=(/usr/src/pkg/applesauce/Makefile.PL /usr/src/pkg/bananabread/Makefile.PL) and then the user can make a meaningful selection from such a list. Now, this is obviously just a guess, and I could be extremely wrong about it. For one thing, they used the variable name "d". That seems to indicate that it should be a list of directories, rather than a list of files. So, perhaps their code is simply *broken*, and where they *thought* they would be getting a list of directories, they actually get a list of mangled useless filenames, because they forgot the -d argument to ls. > | d=(/usr/src/pkg/*/"$1") > > definitely not that, the quotes are wrong in any case They are not! > (but apart from > that, if filename expansion happens in array assignments (it doesn't in > normal ones, and I dislike arrays, so ...) then without the quotes that > might work. > > Alternatively > d=( $( ls -d /usr/src/pkg/*/$1 ) ) This needs quotes around "$1" but yes, it's quite possible that this was their intent. Of course, this is still *broken*, but it only breaks if one of the directory names contains whitespace characters. It's likely that they didn't happen to have any such directories in their test environment, and therefore, this bug would go unnoticed for a long time. > or just > d=( $( printf %s\\n /usr/src/pkg/*/$1 ) ) This is not much better. It still breaks on whitespace. If a list of directories (not their contents) is the desired outcome, then my original code is perfectly fine: d=(/usr/src/pkg/*/"$1") This will expand to something like d=(/usr/src/pkg/vendor1/netcat /usr/src/pkg/vendor2/netcat) > Just to be sure.Personally I'd do > > set -- /usr/src/pkg/*/$1 > > and then simply use the positional parameters. This still needs quotes around "$1", and it's basically the same as the array assignment -- just less flexible, and more suited to sh than bash. But certainly, this is viable in many cases. > Yes. But it turns out not to matter in this case, as none of > the names will ever contain anything but "normal" characters > (no spaces, newlines, asterisks, ...) Famous Last Words™
Re: select syntax violates the POLA
Date:Thu, 1 Apr 2021 11:36:14 -0400 From:Greg Wooledge Message-ID: | On Thu, Apr 01, 2021 at 01:36:59AM -0700, greyw...@starwolf.com wrote: | > The following is valid shell code: | > | > d=($(ls /usr/src/pkg/*/$1)); | | Syntactically valid, but semantically wrong. Greg managed to comment on everything in the original message, except the actual point of it ... Chet answered that, so I won't bother, but: | If $1 is not a directory, then you want: It is a directory, or I'd guess, quite likely a pattern chosen to find where the package that is wanted lives. The '/*/' represents a category grouping, and it is not unusual to not know which one applies to any particular package. My guess is that $1 might be something like *sed* to find any package with "sed" in its name. Or p5-* to select from the perl5 (script) packages. So: | d=(/usr/src/pkg/*/"$1") definitely not that, the quotes are wrong in any case (but apart from that, if filename expansion happens in array assignments (it doesn't in normal ones, and I dislike arrays, so ...) then without the quotes that might work. Alternatively d=( $( ls -d /usr/src/pkg/*/$1 ) ) or just d=( $( printf %s\\n /usr/src/pkg/*/$1 ) ) Just to be sure.Personally I'd do set -- /usr/src/pkg/*/$1 and then simply use the positional parameters. | If $1 is supposed to be a directory, and therefore you want only filenames | and not full pathnames in the array, It is, but he almost certainly wants the directory names, not the contents of the directories. He's going to want the full pathname so once selected, he can cd to it. | > cd ${dir} && | | Quotes. Yes. But it turns out not to matter in this case, as none of the names will ever contain anything but "normal" characters (no spaces, newlines, asterisks, ...) But that's the cd which requires dir to be the full pathname. | > make clean && { | > make update || | > make install; | > } | | Is the inner || supposed to be && by chance? Probably not. This is "if the package is already installed, update it, if not, install it". "make update" will succeed and update the package if needed, if it is installed already, otherwise it will fail. In that case make install will install it (it would fail if a some other version of the package was already installed). (The preceding "make clean" just gets rid of the left overs from any previous compilation, but will fail if there's insufficient permission, or similar, in which case attempting an update or install would also fail). | > if ((n > 1)); then { | > select dir in ${d[@]}; do { | > break; | > } done; | > } | | "${d[@]}" with quotes. Again, yes, but in practice here, not needed. | What purpose do the extra curly braces serve? Good question, wondered that myself. Note that if they were omitted the odd syntax issue wouldn't have arisen, as the done would follow "break;" and be recognised. After all that, and ignoring select's syntax (it was invented by ksh, long long ago, and isn't going to change) it is a dumb interface that can always be coded better using other mechanisms. And when you do that you can allow for much more flexible input than just the line number the select demands. If you avoid select, and avoid arrays, then any Bourne style shell will work. So, do that. kre
Re: select syntax violates the POLA
On Thu, Apr 1, 2021 at 11:25 PM wrote: > > if ((n > 1)); then { > echo "Ambiguous dir specification"; > exit 1; > } > else { > dir=${d[0]}; > } fi; The grouping is unnecessary or should be separate from the first class syntax. Bash is not C or Go and shouldn't be written like it. -- konsolebox
Re: select syntax violates the POLA
On 4/1/21 4:36 AM, greyw...@starwolf.com wrote: Bash Version: 5.1 Patch Level: 4 Release Status: release Description: The 'select' directive's syntax does not correspond to the rest of the shell's syntax. I am not sure if this is by design; if it is, let me know and I'll go away. It's more like `select' doesn't inherit some of the shell's special cases. if ((n > 1)); then { select dir in ${d[@]}; do { break; } done; } else { ... ...but select breaks on the "} done;" syntax Yes, you need a list terminator so that `done' is recognized as a reserved word here. `;' is sufficient. Select doesn't allow the `done' unless it's in a command position. Some of the other compound commands have special cases, mostly inherited from the Bourne shell, to allow it. -- ``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: select syntax violates the POLA
On Thu, Apr 01, 2021 at 01:36:59AM -0700, greyw...@starwolf.com wrote: > The following is valid shell code: > > d=($(ls /usr/src/pkg/*/$1)); Syntactically valid, but semantically wrong. If $1 is not a directory, then you want: d=(/usr/src/pkg/*/"$1") If $1 is supposed to be a directory, and therefore you want only filenames and not full pathnames in the array, then we can arrange for that as well, but it's slightly more tedious. Using ls here is wrong, and will break. It's Pitfall #1 on my list for a reason. https://mywiki.wooledge.org/BashPitfalls#pf1 > cd ${dir} && Quotes. > make clean && { > make update || > make install; > } Is the inner || supposed to be && by chance? > if ((n > 1)); then { > select dir in ${d[@]}; do { > break; > } done; > } "${d[@]}" with quotes. What purpose do the extra curly braces serve? Do you want them just because you think they look pretty? > until [ -f ${tmpfile} ]; do { Quotes. And again, those extra curly braces don't serve any purpose. > for dir in ${d[@]}; do { Quotes.
select syntax violates the POLA
Configuration Information [Automatically generated, do not change]: Machine: x86_64 OS: netbsd Compiler: gcc Compilation CFLAGS: -O2 -I/usr/local/include -D_FORTIFY_SOURCE=2 -I/usr/include uname output: NetBSD eddie.starwolf.com 9.99.81 NetBSD 9.99.81 (EDDIE) #9: Tue Mar 23 19:13:25 PDT 2021 greyw...@eddie.starwolf.com:/sys/native/compile/EDDIE amd64 Machine Type: x86_64--netbsd Bash Version: 5.1 Patch Level: 4 Release Status: release Description: The 'select' directive's syntax does not correspond to the rest of the shell's syntax. I am not sure if this is by design; if it is, let me know and I'll go away. The following is valid shell code: d=($(ls /usr/src/pkg/*/$1)); n=${#d[@]}; if ((n > 1)); then { echo "Ambiguous dir specification"; exit 1; } else { dir=${d[0]}; } fi; cd ${dir} && make clean && { make update || make install; } I'd like to replace the first part of the if/else/fi with: if ((n > 1)); then { select dir in ${d[@]}; do { break; } done; } else { ... ...but select breaks on the "} done;" syntax that works with, e.g., while sleep 5; do { date; } done; until [ -f ${tmpfile} ]; do { sleep 5; } done; for dir in ${d[@]}; do { echo ${dir}; } done; This violates the POLA, from my point of view. Repeat-By: d=($(ls /usr/src/pkg/*/$1)); select dir in ${d[@]}; do { break; } done;