bash string quoted multi-word args to array -
the question:
in bash scripting, best way convert string, containing literal quotes surrounding multiple words, array same result of parsed arguments?
the controversy:
many questions exist applying evasive tactics avoid problem instead of finding solution, question raises following arguments , encourage reader focus on arguments , if it, partake in challenge find optimum solution.
arguments raised:
- although there many scenarios pattern should avoided, because there exists alternative solutions better suited, author of opinion valid use cases still remain. question attempt produce 1 such use case, make no claim viability thereof conceivable scenario may present in real world situation.
- you must find optimum solution satisfy requirement. use case chosen real world applications. may not agree decisions made not tasked give opinion deliver solution.
- satisfy requirement without modifying input or choice of transport. both chosen real world scenario defend narrative parts out of control.
- no answers exist particular problem , question aims address that. if inclined avoid pattern avoid question if think challenge lets see how approach problem.
the valid use case:
converting existing script in use receive parameters via named pipe or similar stream. in order minimize impact on myriad of scripts outside of developers control decision made not change interface. existing scripts must able pass same arguments via new stream implementation did before.
existing implementation:
$ ./string2array arg1 arg2 arg3 args=( [0]="arg1" [1]="arg2" [2]="arg3" )
required change:
$ echo "arg1 arg2 arg3" | ./string2array args=( [0]="arg1" [1]="arg2" [2]="arg3" )
the problem:
as pointed out bash , double-quotes passing argv literal quotes not parsed expected.
this workbench script can used test various solutions, handles transport , formulates measurable response. suggested focus on solution script gets sourced string argument , should populate $args variable array.
the string2array workbench script:
#!/usr/bin/env bash #string2arry args=() function inspect() { local inspct=$(declare -p args) inspct=${inspct//\[/\\n\\t[}; inspct=${inspct//\'/}; inspct="${inspct:0:-1}\n)" echo -e ${inspct#*-a } } while read -r; # source solution turn $reply in $args array source $1 "${reply}" inspect done
standard solution - fails
the solution turning string space delimited array of words worked our first example above:
#solution1 args=($@)
undesired result
unfortunately standard solution produces undesired result quoted multi word arguments:
$ echo 'arg1 "multi arg 2" arg3' | ./string2array solution1 args=( [0]="arg1" [1]="\"multi" [2]="arg" [3]="2\"" [4]="arg3" )
the challenge:
using workbench script provide solution snippet produce following result arguments received.
desired result:
$ echo 'arg1 "multi arg 2" arg3' | ./string2array solution-xyz args=( [0]="arg1" [1]="multi arg 2" [2]="arg3" )
the solution should compatible standard argument parsing in every way. following unit test should pass for provided solution. if can think of missing unit test please leave comment , can update it.
unit test requirements
update: test simplified , includes johnathan leffer test
#!/usr/bin/env bash #test_string2array solution=$1 function test() { cmd="echo \"${1}\" | ./string2array $solution" echo "$ ${cmd}" echo ${1} | ./string2array $solution > /tmp/t cat /tmp/t echo -n "result : " [[ $(cat /tmp/t|wc -l) -eq 7 ]] && echo "passed!" || echo "failed!" } echo 1. testing single args test 'arg1 arg2 arg3 arg4 arg5' echo echo 2. testing multi args \" quoted test 'arg1 "multi arg 2" arg3 "a r g 4" arg5' echo echo 3 testing multi args \' quoted test "arg1 'multi arg 2' arg3 'a r g 4' arg5" echo echo 4 johnathan leffer test test "he said, \"don't that!\" \"they didn't listen.\""
the declare
built-in seems want; in test, it's inspect
function doesn't seem work test inputs:
# solution3 declare -a "args=($1)"
then
$ echo "arg1 'arg2a arg2b' arg3" | while read -r; > source solution3 "${reply}" > arg in "${args[@]}"; > echo "arg $((++i)): $arg" > done > done arg 1: arg1 arg 2: arg2a arg2b arg 3: arg3
Comments
Post a Comment