Re: parameter expansion with `:` does not work

2021-07-07 Thread Greg Wooledge
On Thu, Jul 08, 2021 at 04:38:25AM +0200, lisa-as...@perso.be wrote:
> I'd rather understand what's going on, rather than simply never use it.

OK.  Let's start from the beginning.

In sh and bash, anything that begins with a $ is potentially a
substitution, a.k.a. an expansion.  The parser will try to unravel
the punctuation soup to figure out where the beginning and ending of
the substitution are.  Then, that piece of the command will be replaced
with zero or more words.  All of it is dependent on context, and rules
that have grown organically and chaotically over a span of decades.

Let's say you have a command like this:

foo $bar

The thing on the right hand side, which begins with $ and ends with r,
is a substitution.  Specifically, it's a parameter expansion, which means
a "parameter" (which is either a variable or a special parameter, in this
case a variable) will have its value pulled from memory and used for the
substitution.

If we have a variable named bar, its value gets substituted into the
command.  Since $bar is not quoted, that value undergoes two more rounds
of substitutions (word splitting, and filename expansion).  At the end
of all that action, we will have a list of zero or more words, and these
words will become the arguments of the foo command.

OK so far?  Good.

Now let's say we have this command:

: $bar

Once again, the value of the variable named bar is substituted, and then
undergoes word splitting and filename expansion, and the results of that
become the arguments to the : command.

The : command does nothing, so the end result of all this work is ...
nothing.  Except that we may hit the file system a few times in order to
perform filename expansions, if there are any glob characters in the
variable's value.  But that's it.

So, why would anyone write a command like this?  It's because some
substitutions have side effects.

Let's look at this command next:

: $((x++))

Now, this is a silly command, and you wouldn't write this in real life,
because it's just more complex than it needs to be.  But I'm demonstrating
something, so stick with it for a moment, please.

This time, we don't have a parameter expansion.  We have an arithmetic
substitution instead.

The stuff inside the $(( )) gets passed to a special arithmetic parser,
which has its own special rules.  These rules look a lot like the rules
of the C language, by some strange coincidence.

This particular arithmetic expression x++ uses the post-increment operator
++ to add 1 to the value of an existing (or even nonexistent) variable.
This is a *side effect*, meaning that it does something more than just
producing a value for our substitution.  It has some lasting effect.

So, what happens here?  In order:

1) The value of x is pulled from memory and stored in a temporary spot.
   If x doesn't exist, we use the value 0.  If x contains a string that
   can be treated as an integer, we use that value.  Otherwise, we attempt
   to perform recursive arithmetic evaluation.  We won't cover all of that
   right now.

2) We take the value from step 1, add 1 to it, and store this back into x.

3) The value from step 1 (before we added 1) is used as the value of the
   substitution.

4) The value of the substitution would undergo word splitting and filename
   expansion because of the lack of quotes, except that the result of
   an arithmetic expansion is always an integer, and therefore can't do
   those things.

5) The value of the substitution is used as the argument of the : command,
   which does nothing.

So, the whole point of this demonstration was what happens in step 2.  The
value of x is changed, even though we used a command that normally does
nothing.  The change happens *during* the expansion.  It's independent of
the command that we used.

The only reason we have the : command here at all, is so that we don't
try to execute the value of x as a command.  If we left out the : we
would get something like

bash: 0: command not found

We don't want that.  So that's why the : is there.

Now that you understand everything that's going on, let's look at this
crazy shit from 1977 that you've fallen in love with:

: ${foo:=bar}

What happens here?  We have a parameter expansion with a special modifier.
According to the documentation which has been quoted at you multiple
times already, this is a two-step expansion.  The value of the variable
named foo is pulled from memory.  If this value is the empty string, or
if the variable foo does not currently exist, then an *assignment* takes
place, and the string bar is stored in the variable foo, and then that
string (bar) also becomes the value of the substitution.

So, we perform the following steps:

1) The value of the variable foo is pulled from memory.

2) If the value from step 1 is the empty string (or if there's no variable
   named foo yet), the string bar is *assigned* to the variable foo, and
   the string bar also becomes the value that we pulled from memory.

3) The 

Re: parameter expansion with `:` does not work

2021-07-07 Thread Lawrence Velázquez
> On Jul 7, 2021, at 10:38 PM, lisa-as...@perso.be wrote:
> 
> Correct.  How do others customarily use `${fdir:=$PWD}` ?

The common idiom is

: "${fdir:=$PWD}"

The ':' utility is used because it does nothing, but its arguments
are expanded as usual.

> I'd rather understand what's going on, rather than simply never use it.

Think about what is happening here:

fdir=${fdir:=$PWD}

This is conceptually equivalent to

if [[ -z "$fdir" ]]; then
fdir="$PWD"
fi
fdir="$fdir"

I hope you can see why this is a pointless thing to do.

-- 
vq



Re: parameter expansion with `:` does not work

2021-07-07 Thread Kerin Millar
On Thu,  8 Jul 2021 02:54:06 +0200 (CEST)
lisa-as...@perso.be wrote:

> As I was in it, have also changed  
> 
> 
> 
> fdir=${fdir:-$PWD}

This makes sense.

> 
> 
> 
> to 
> 
> 
> 
> fdir=${fdir:=$PWD} 

Here, you are using a form of parameter expansion that intrinsically performs 
variable assignment, only to redundantly assign the result of the expansion to 
the same variable once again. In a roundabout fashion, it ends up proving 
Greg's point. I'd suggest temporarily disavowing yourself of the 
${parameter:=word} form, for the time being.

-- 
Kerin Millar



Re: parameter expansion with `:` does not work

2021-07-07 Thread Greg Wooledge
> > fdir=${fdir:=$PWD}
> 
> Ack!

I know.  I simply gave up.  At least this will "work", even if it's
completely silly.



Re: parameter expansion with `:` does not work

2021-07-07 Thread Dennis Williamson
On Wed, Jul 7, 2021, 7:55 PM  wrote:

>
>
> Things are clearer now.
>
>
>
> > Seriously, just replace the :- expansion with := and go on with your
> code.
> > It's the least intrusive change, and won't disturb your logic.
>
>
>
>  I executed
>
>
>
> echo "${parameter:-word}"; echo "${parameter}"
>
>
>
> and then
>
>
>
> echo "${parameter:=word}"; echo "${parameter}"
>
>
>
> It was to make the distinction clear.
>
>
>
> As I was in it, have also changed
>
>
>
> fdir=${fdir:-$PWD}
>
>
>
> to
>
>
>
> fdir=${fdir:=$PWD}
>
>
>
>


Ack!


Re: parameter expansion with `:` does not work

2021-07-07 Thread Chet Ramey

On 7/7/21 6:53 PM, lisa-as...@perso.be wrote:


Yes I can see one has :- and the other has  :=

But I also noticed : at the front, with someone saying that the command does not
exist in Gnu Bash.


No one implied that `the command' is not present in bash.

Seriously, just replace the :- expansion with := and go on with your code.
It's the least intrusive change, and won't disturb your logic.

--
``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: parameter expansion with `:` does not work

2021-07-07 Thread Greg Wooledge
On Thu, Jul 08, 2021 at 12:33:04AM +0200, lisa-as...@perso.be wrote:
> Talking about neater design choices, you seem to imply you have some other
> way to take user options that are composed of lists, so that one does not use
> a delimited string. What is it?

I wrote a detailed message containing many different choices:

https://lists.gnu.org/archive/html/help-bash/2021-07/msg00019.html



Re: parameter expansion with `:` does not work

2021-07-07 Thread Chet Ramey

On 7/7/21 6:48 PM, lisa-as...@perso.be wrote:



I have some difficulty understanding the difference between ${parameter:-word} 
and ${parameter:=word}, and when it is appropriate to use one as opposed to the 
other.


Dennis Williamson succinctly summarized the differences.


${parameter:-word}
If parameter is unset or null, the expansion of word is substituted. 



${parameter:=word}
If parameter is unset or null, the expansion of word is assigned to parameter. The value of parameter is then substituted. 


The key difference is in the first sentence of each description.

--
``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: parameter expansion with `:` does not work

2021-07-07 Thread Greg Wooledge
On Thu, Jul 08, 2021 at 12:37:07AM +0200, lisa-as...@perso.be wrote:

> >From: Dennis Williamson 
> >$ : ${foo:-bar}
> >$ : ${foo:=bar}
> >The first form is a substitution and the second form is an assignment.

> So you used `:` at the beginning and it worked?

Are you incapable of seeing the difference between the two lines?

I weep for the human race.  There's no telling what you're even seeing
on your monitor (assuming you can see, and aren't using a screen reader).
You're clearly using some mail user agent that works like Microsoft Outlook,
and there's no guessing what it's doing to the messages you receive.

If you literally cannot see the difference between :- and := in the
above example, then all is lost, and there is nothing more we can say
to you.  Because you can't see it.



Re: parameter expansion with `:` does not work

2021-07-07 Thread Lawrence Velázquez
On Wed, Jul 7, 2021, at 6:37 PM, lisa-as...@perso.be wrote:
> So you used `:` at the beginning and it worked?

Chet and Greg already spelled out your mistake.  It has nothing to
do with the ':' command.

-- 
vq



Re: parameter expansion with `:` does not work

2021-07-07 Thread Dennis Williamson
On Wed, Jul 7, 2021, 4:50 PM  wrote:

>
> Have noticed that parameter expansion with `:` does not work
>
>
>
> : ${fltype:-"texi,org"}  # alternative to `fltype=`
>
>


$ unset foo
$ : ${foo:-bar}
$ echo "$foo"

$ : ${foo:=bar}
$ echo "$foo"
bar

The first form is a substitution and the second form is an assignment.


Re: parameter expansion with `:` does not work

2021-07-07 Thread Greg Wooledge
On Thu, Jul 08, 2021 at 12:10:27AM +0200, lisa-as...@perso.be wrote:
> The line 
> : ${fltype:-"texi,org"}  
> should be an alternative to 
> fltype=${fltype:-"texi,org"}  

As Chet guessed earlier, you probably meant := instead of :- .

I started typing something to that effect in my first response, but then
I noticed the payload you were "assigning" (though you messed up the
syntax) and decided to try to teach you to fish, rather than tossing
you the decrepit, smelly old fish you had dropped in the dirt.

You are using horrible syntax to do the *wrong thing*.

Lists should be stored in indexed array variables, not in strings with
silly delimiters.

Initialize an array variable holding the default list of extensions at
the beginning of your program.  Then, in your option-processing code,
if the user supplies their own delimited list of extensions, split it
apart and use the resulting list to overwrite the array variable.

That's it.  No need for 40-year-old crappy syntax.  No need to store
your default list as a delimited string and then spend system resources
splitting it apart.  You only need to expend those resources if the user
supplies a delimited list, and the user only needs to do that because of
the crappy design choices you've made.

But since the user is you, if that's how you *really* want the program
to work, then so be it.  Just don't make it even worse than it needs to
be.



Re: parameter expansion with `:` does not work

2021-07-07 Thread Chet Ramey

On 7/7/21 6:12 PM, lisa-as...@perso.be wrote:


 > : ${fltype:-"texi,org"}  # alternative to `fltype=` >

I'm not sure why you think that's an alternative. Maybe you meant
${fltype:="texi,org"}?

It is supposed to be built into bash so a new process is not created.
Perhaps not in Gnu Bash?


What are you talking about? What do you think you're saying?

--
``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: parameter expansion with `:` does not work

2021-07-07 Thread Chet Ramey

On 7/7/21 6:10 PM, lisa-as...@perso.be wrote:


The line

: ${fltype:-"texi,org"}

should be an alternative to
 
fltype=${fltype:-"texi,org"}


It absolutely is not.

--
``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: parameter expansion with `:` does not work

2021-07-07 Thread Chet Ramey

On 7/7/21 5:50 PM, lisa-as...@perso.be wrote:


Have noticed that parameter expansion with `:` does not work



: ${fltype:-"texi,org"}  # alternative to `fltype=` >


I'm not sure why you think that's an alternative. Maybe you meant
${fltype:="texi,org"}?

--
``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: parameter expansion with `:` does not work

2021-07-07 Thread Greg Wooledge
On Wed, Jul 07, 2021 at 11:50:01PM +0200, lisa-as...@perso.be wrote:
> Have noticed that parameter expansion with `:` does not work
> 
> : ${fltype:-"texi,org"}  # alternative to `fltype=`

What did it do?  What did you *expect* it to do?

This looks like it's related to your ongoing project to make your
simple script as complex as possible.  As such, it appears you're
digging into the bowels of the Bourne shell and trying to dig up
every obscure piece of syntax you can find, so that you can use
them all, to be completely sure you can't possibly read the script
a week from now.

I advise you to stop doing this.

In this particular instance, you're assigning a LIST of two values
to a STRING variable, using a comma as a delimiter between them.
Presumably you're going to split this list apart later on.

Wouldn't it be a whole lot simpler to store the list in an ARRAY
variable in the first place, and avoid the need to split it?