Question

I am writing a bash script that loops over the output of a command substitution and then tries to perform another command substitution within the loop body. Here is the code:

#!/usr/bin/bash

IFS=$'\n' 

for i in $( xmllint --xpath "string(/*[local-name()='Project'])" gsGDAL/gsGDAL.vcxproj.user )
do
   IFS=' ' #attempted with and without this line
   "$( awk -F= '{printf("export %s=\"%s\"", $1, $2)}' <(echo $i) )"
   IFS=$'\n' #attempted with and without this line
done

I set the IFS to newline so that the loop iterates over each LINE of output of the xmllint command rather than iterating over each space-separated word. However, that makes the command substitution within the loop fail. Some debugging led to the conclusion that the essence of the problem is this:

#!/usr/bin/bash

IFS=$'\n'

$(echo export TEST="test")

which gives the error:

./x.sh: line 6: export TEST=test: command not found

You can see that I attempted a fix in the first code example by resetting IFS within the loop. That did not work.

I realize that I can solve the problem using a different idiom for the script.
e.g. process substituting the xmllint command to awk instead of doing awk on each individual line to name one possibility. Comments to that effect are welcome, however please submit answers relevant to the following:

  1. Why does setting IFS to newline mess up the command substitution generated export?
  2. Why does resetting IFS in the loop not fix the problem?

UPDATE: Per the discussion with Barmar, IFS is used for word-splitting after command/variable expansion.

Était-ce utile?

La solution

I don't think IFS is the cause of your problems. There are two problems with your code:

  1. You put $(awk ...) in double quotes, so no word splitting is done. So it treats export varname="value" as the name of the command -- the space is part of the command name, not a separator between the command and the argument.

  2. Even without the double quotes, it wouldn't work because quote processing is not performed on the result of command substitution, only word splitting and wildcard expansion are done. So the double quotes in your export command will be included as literal characters in the values being assigned.

The solution to this, as pointed out by mplf, is to use eval:

eval "$(awk -F= '{printf("export %s=\"%s\"", $1, $2)}' <(echo $i) )"

Autres conseils

Use eval to evaluate the string being returned from the subshell.

IFS=' ' #attempted with and without this line
eval $( awk -F= '{printf("export %s=\"%s\"", $1, $2)}' <(echo $i) )
IFS=$'\n' #attempted with and without this line
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top