Edit: Mostly rewritten for clarity/digestibility. Also, I found one possible answer using xargs. I prefer avoiding the external command--I'll only accept my own answer if no alternative turns up.
I'm trying to pass the output of local
(declared local variables as a newline-delimited key=value
list), back to another invocation of local, but I'm bumping up against the edge of my understanding of bash quoting/escaping.
It's easy to handle values with no spaces, but values with internal spaces cause quoting/splitting trouble. Easier to show than tell. Using BASH_VERSION=4.4.23(1)-release
. I'll walk through the steps; there's a longer repro script at the end of the post.
- Define some local variables, and print them with the
local
builtin:
Which outputs some variation of:function export_locals(){ local one=1 local two=$(echo word1 word2) local three=$(echo "word1 ain't word2") local # aka local -p }
one=1 three='word1 ain'\''t word2' two='word1 word2'
- Call
export_locals
from another function, and pass the output to another invocation of thelocal
builtin:
With the defaultfunction import_locals(){ local $(export_locals) local }
IFS
, this will fail.set -x
shows the cause:
Using+ local one=1 'three='\''word1' 'ain'\''\'\'''\''t' 'word2'\''' 'two='\''word1' 'word2'\''' bash: local: `ain'\''t': not a valid identifier bash: local: `word2'': not a valid identifier bash: local: `word2'': not a valid identifier
IFS=$'\n'
keeps it from splitting the values oftwo
orthree
, but they end up with bonus single quotes:
At this point+ local one=1 'three='\''word1 ain'\''\'\'''\''t word2'\''' 'two='\''word1 word2'\''' + local one=1 three=''\''word1 ain'\''\'\'''\''t word2'\''' two=''\''word1 word2'\'''
echo $two
would output'word1 word2'
I'm looking for ways to remove the spare quotes that won't break the field splitting, won't break on more complex inputs like $three
, and ideally don't rely on external commands. I also prefer not screwing with the IFS, but I don't think that's in the cards.
#!/usr/bin/env bash
set -x
# declare 2 vars and export them
function export_locals(){
local one=1
local two=$(echo word1 word2)
local three=$(echo "word1 ain't word2")
local # aka local -p
}
# insert vars into different local namespace
function import_locals(){
echo ${one:-nah} ${two:-nope} # nothing up my sleeve
local $(export_locals)
local
echo ${one:-nah} ${two:-nope} ${three:-nope}
}
function test_export_import_locals(){
export_locals # just to show what it prints
import_locals # bad attempt
IFS=$'\n' import_locals # good (ish?) attempt
}