LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   " in a Bash here-document (https://www.linuxquestions.org/questions/programming-9/in-a-bash-here-document-4175656851/)

Reuti 07-04-2019 05:34 AM

" in a Bash here-document
 
Hi,

I stumbled about an issue where quotation marks are either removed or output including the escape character:

Code:

CMDOPT_F=1
FILES="MRCONEE MDCINT"
cat <<EOF > script
line 1
pam${CMDOPT_F+ --get="${FILES}"}
line 3
EOF
cat script

will result in:
Code:

line 1
pam --get=MRCONEE MDCINT
line 3

which is the result as the quotation marks are removed – okay. So the variant:

Code:

CMDOPT_F=1
FILES="MRCONEE MDCINT"
cat <<EOF > script
line 1
pam${CMDOPT_F+ --get=\"${FILES}\"}
line 3
EOF
cat script

might help, but the output is:
Code:

line 1
pam --get=\"MRCONEE MDCINT\"
line 3

I would have expected that the escape characters are removed, once they were used.

I succeeded by using a variable for the quotation mark:
Code:

QUOTE=\"
CMDOPT_F=1
FILES="MRCONEE MDCINT"
cat <<EOF > script
line 1
pam${CMDOPT_F+ --get=${QUOTE}${FILES}${QUOTE}}
line 3
EOF
cat script

Code:

line 1
pam --get="MRCONEE MDCINT"
line 3

which is the desired ouptut. But I’m still puzzled, why the \" ended up in the script in the second case.

-- Reuti

Keith Hedger 07-04-2019 05:45 AM

it seems to be this construct
Code:

pam${CMDOPT_F+ --get="${FILES}"}
Use
Code:

pam --get="$FILES"
Instead gives
Code:

#!/bin/bash -e

#©keithhedger Thu 4 Jul 11:39:22 BST 2019 kdhedger68713@gmail.com
CMDOPT_F=1
FILES="MRCONEE MDCINT"
cat <<EOF > script
line 1
#pam${CMDOPT_F+ --get="${FILES}"}
pam --get="$FILES"
line 3
EOF
cat script

line 1
pam --get="MRCONEE MDCINT"
line 3


Reuti 07-04-2019 05:59 AM

Quote:

Originally Posted by Keith Hedger (Post 6011824)
it seems to be this construct
Code:

pam${CMDOPT_F+ --get="${FILES}"}
Use
Code:

pam --get="$FILES"

Hi Keith,

Thx for looking into this. The construct ${parameter+word} is used here, as I want the --get option only in case CMDOPT_F was set. Otherwise nothing should be appended. Sorry for neglecting this prerequisite.

-- Reuti

Keith Hedger 07-04-2019 08:40 AM

in which case you are using the wrong construct this is the correct way to set a default value to a variable in bash
Code:

echo ${MYVAR:-"Default Val"}
Default Val
MYVAR="another val"
echo ${MYVAR:-"Default Val"}
another val


David the H. 07-04-2019 10:43 AM

There are four variations for alternate values in variable expansion. From man bash:

Code:

${parameter:-word}
    Use Default Values.  If parameter is unset or null, the expansion of word is substituted.  Otherwise, the value of parameter is substituted.

${parameter:=word}
    Assign  Default  Values.  If  parameter  is  unset or null, the expansion of word is assigned to parameter.  The value of parameter is then substituted.  Positional parameters and special parameters may not be assigned to in this way.

${parameter:?word}
    Display  Error if Null or Unset.  If parameter is null or unset, the expansion of word (or a message to that effect if word is not present) is written to the standard error and the shell, if it is not interactive, exits.  Otherwise, the value of parameter is substituted.

${parameter:+word}
    Use Alternate Value.  If parameter is null or unset, nothing is substituted, otherwise the expansion of word is substituted.

If the colon is omitted, it will only test for empty values, and not react to null (unset) variables.


You can nest quotes inside parameter substitutions, so I believe you want to use the version I supply below.



As for heredocs, I have personally come to dislike them, for the most part. I find them hard to set up correctly and awkward to read. My preference is usually to use an array, with each index holding one line of text.

Code:

CMDOPT_F=1
FILES='MRCONEE MDCINT'

## start script array ##

script[0]='line 1'
script[1]="pam${CMDOPT_F:+" --get='$FILES'"}"
script[2]='line 3'

## end script array ##

printf '%s\n' "${script[@]}" > script

Result:
Code:

line 1
pam --get='MRCONEE MDCINT'
line 3

BTW, you might just skip the extra variable and test the FILES variable directly, if that would suit you better.

Code:

myscript+=( "pam${FILES:+" --get='$FILES'"}" )

Keith Hedger 07-04-2019 02:25 PM

[QUOTE=David the H.;6011913]There are four variations for alternate values in variable expansion. From man bash:

Code:

...

${parameter:=word}
    Assign  Default  Values.  If  parameter  is  unset or null, the expansion of word is assigned to parameter.  The value of parameter is then substituted.  Positional parameters and special parameters may not be assigned to in this way.

${parameter:?word}
    Display  Error if Null or Unset.  If parameter is null or unset, the expansion of word (or a message to that effect if word is not present) is written to the standard error and the shell, if it is not interactive, exits.  Otherwise, the value of parameter is substituted.

${parameter:+word}
    Use Alternate Value.  If parameter is null or unset, nothing is substituted, otherwise the expansion of word is substituted.

...

Not seen these before, is it new? You learn something new every day :)

grail 07-04-2019 11:55 PM

Is there a reason you cannot switch to single quotes?
This worked for me:
Code:

CMDOPT_F=1
FILES="MRCONEE MDCINT"
cat <<EOF>script
line 1
pam${CMDOPT_F+ --get='${FILES}'}
line 3
EOF
cat script

Shellcheck does complain about it but I don't think it understands here-doc rules ;)

MadeInGermany 08-01-2019 12:23 PM

What bash version?
I have seen such incorrect parsing in bash-3 that got corrected in bash-4.

Reuti 08-02-2019 03:11 PM

Quote:

Originally Posted by grail (Post 6012081)
Is there a reason you cannot switch to single quotes?

No, but this was indeed the cure. Nevertheless I was looking for an explanation about the observed behavior.

-- Reuti

Reuti 08-02-2019 03:13 PM

Quote:

Originally Posted by MadeInGermany (Post 6020582)
What bash version?
I have seen such incorrect parsing in bash-3 that got corrected in bash-4.

It was version 4.2.42(1), but I even compiled just the 5.0 version and the effect is still the same.

-- Reuti


All times are GMT -5. The time now is 10:30 PM.