This is a continuation of awk gsub not replacing all instances of period in field.
I have some input:
$ cat ./ipv4settings.txt
ipv4.gateway: 192.168.2.1
ipv4.routes: --
ipv4.route-metric: -1
ipv4.route-table: 0 (unspec)
I'm able to generate the desired output (somewhat):
$ awk 'BEGIN{FS=":[[:space:]]+";OFS="="}{gsub("[.]|-","_",$1);$1=$1;print $1"="$2 }' ./ipv4settings.txt
ipv4_gateway=192.168.2.1
ipv4_routes=--
ipv4_route_metric=-1
ipv4_route_table=0 (unspec)
What I want to do next is declare variables for each line of output. I have used several variations using declare
:
$awk 'BEGIN{FS=":[[:space:]]+";OFS="="}{gsub("[.]|-","_",$1);$1=$1;print $1"="$2 }' ./ipv4settings.txt
ipv4_gateway=192.168.2.1
ipv4_routes=--
ipv4_route_metric=-1
ipv4_route_table=0 (unspec)
$ declare $( awk 'BEGIN{FS=":[[:space:]]+";OFS="="}{gsub("[.]|-","_",$1);$1=$1;print $1"="$2 }' ./ipv4settings.txt )
-bash: declare: `(unspec)': not a valid identifier
I tried quoting the entire line of output from awk
(declare not a valid identifier bash)(https://www.baeldung.com/linux/awk-print-quote-characters):
$ awk 'BEGIN{FS=":[[:space:]]+";OFS="="}{gsub("[.]|-","_",$1);$1=$1;print "\042"$1"="$2"\042" }' ./ipv4settings.txt
"ipv4_gateway=192.168.2.1"
"ipv4_routes=--"
"ipv4_route_metric=-1"
"ipv4_route_table=0 (unspec)"
$ declare $( awk 'BEGIN{FS=":[[:space:]]+";OFS="="}{gsub("[.]|-","_",$1);$1=$1;print "\042"$1"="$2"\042" }' ./ipv4settings.txt )
-bash: declare: `"ipv4_gateway=192.168.2.1"': not a valid identifier
-bash: declare: `"ipv4_routes=--"': not a valid identifier
-bash: declare: `"ipv4_route_metric=-1"': not a valid identifier
-bash: declare: `"ipv4_route_table=0': not a valid identifier
-bash: declare: `(unspec)"': not a valid identifier
... or just the value portion:
$ awk 'BEGIN{FS=":[[:space:]]+";OFS="="}{gsub("[.]|-","_",$1);$1=$1;print $1"=\042"$2"\042" }' ./ipv4settings.txt
ipv4_gateway="192.168.2.1"
ipv4_routes="--"
ipv4_route_metric="-1"
ipv4_route_table="0 (unspec)"
$ declare $( awk 'BEGIN{FS=":[[:space:]]+";OFS="="}{gsub("[.]|-","_",$1);$1=$1;print $1"=\042"$2"\042" }' ./ipv4settings.txt )
-bash: declare: `(unspec)"': not a valid identifier
How do I get declare
to work with a variable value with a space?
Modifying my answer to OP's previous question:
$ cat ipv4.awk
BEGIN { sq = "\x27" }
#######
# if 1st field will convert to an invalid variable name then print
# a message to stderr (printing to stdout will cause problems with
# the follow-on source call)
! ($1 ~ /^[[:alnum:]._-]+:/) {
print "ERROR: Invalid entry:",$0 > "/dev/stderr"
next
}
/^ipv4[.](gateway|route)/ {
pos = index($0,":")
var = substr($0,1,pos-1)
value = substr($0,pos+1)
gsub(/[.-]/,"_",var)
gsub(/^[[:space:]]*|[[:space:]]*$/,"",value)
gsub(sq,sq "\"" sq "\"" sq,value) # see NOTES below
print var "=" sq value sq
}
NOTES:
gsub(sq,sq "\"" sq "\"" sq,value)
call ...gsub()
call has been added to address potential injection attacksgsub(/[']/,"'\"'\"'",value)
could also be used but must be placed in a file (eg, ipv4.awk
) and invoked via awk -f ipv4.awk
; calling gsub(/[']/,"'\"'\"'",value)
from an inline awk
script (eg, OP's example awk
scripts) will generate syntax errors (due to the special nature of the single quote for inline awk
scripts)Adding some additional (bogus) lines on the end (borrowing a few from Charles Duffy's answer):
$ cat ipv4settings.txt
ipv4.gateway: 192.168.2.1
ipv4.routes: --
ipv4.route-metric: -1
ipv4.route-table: 0 (unspec)
ipv6.routes: should ignore this line
ipv4.route-wifi.network-ssid-name: hi$(touch evil)'$(touch evil)'\
ipv4.route-evil.variable.$(touch evil): harmless
ipv4.route-example.with.colons: hi:world: yup: still data
ipv4.route-stuff:0 (unspec) * "'leave:these:colons:alone
NOTE: the last line has a few spaces on the end
Generating the variable=value
pairs:
$ awk -f ipv4.awk ipv4settings.txt
ipv4_gateway='192.168.2.1'
ipv4_routes='--'
ipv4_route_metric='-1'
ipv4_route_table='0 (unspec)'
ipv4_route_wifi_network_ssid_name='hi$(touch evil)'"'"'$(touch evil)'"'"'\'
ERROR: Invalid entry: ipv4.route-evil.variable.$(touch evil): harmless
ipv4_route_example_with_colons='hi:world: yup: still data'
ipv4_route_stuff='0 (unspec) * "'"'"'leave:these:colons:alone'
One idea using source
to load the variables into the current environment:
$ source <(awk -f ipv4.awk ipv4settings.txt)
ERROR: Invalid entry: ipv4.route-evil.variable.$(touch evil): harmless
$ typeset -p ipv4_gateway ipv4_routes ipv4_route_metric ipv4_route_table ipv4_route_wifi_network_ssid_name ipv4_route_example_with_colons ipv4_route_stuff
declare -- ipv4_gateway="192.168.2.1"
declare -- ipv4_routes="--"
declare -- ipv4_route_metric="-1"
declare -- ipv4_route_table="0 (unspec)"
declare -- ipv4_route_wifi_network_ssid_name="hi\$(touch evil)'\$(touch evil)'\\"
declare -- ipv4_route_example_with_colons="hi:world: yup: still data"
declare -- ipv4_route_stuff="0 (unspec) * \"'leave:these:colons:alone"