【发布时间】:2014-04-13 01:31:09
【问题描述】:
问题:
在 bash 脚本中,将包含围绕多个单词的文字引号的字符串转换为具有相同解析参数结果的数组的最佳方法是什么?
争议:
存在许多问题都采用规避策略来避免问题而不是找到解决方案,这个问题提出了以下论点,并希望鼓励读者专注于论点,如果您愿意,请参与挑战找到最优解。
提出的论点:
- 尽管有很多场景应该避免这种模式,但由于存在更适合的替代解决方案,作者认为仍然存在有效的用例。这个问题将尝试产生一个这样的用例,但不声称它的可行性,只是说它是一个可以想象的场景,可能会出现在现实世界的情况下。
- 您必须找到满足要求的最佳解决方案。该用例是专门为其实际应用选择的。您可能不同意所做出的决定,但您并没有任务仅提供意见以提供解决方案。
- 无需修改输入或传输选择即可满足要求。两者都是根据真实世界场景专门选择的,以捍卫那些部分不受您控制的叙述。
- 没有针对特定问题的答案,本问题旨在解决该问题。如果您倾向于避免这种模式,那么只需避免该问题,但如果您认为自己已准备好迎接挑战,那么让我们看看您将如何解决问题。
有效用例:
将当前使用的现有脚本转换为通过命名管道或类似流接收参数。为了尽量减少对开发人员控制之外的无数脚本的影响,决定不更改界面。现有脚本必须能够像以前一样通过新的流实现传递相同的参数。
现有实现:
$ ./string2array arg1 arg2 arg3
args=(
[0]="arg1"
[1]="arg2"
[2]="arg3"
)
需要更改:
$ echo "arg1 arg2 arg3" | ./string2array
args=(
[0]="arg1"
[1]="arg2"
[2]="arg3"
)
问题:
正如Bash and Double-Quotes passing to argv 指出的那样,文字引号未按预期进行解析。
此工作台脚本可用于测试各种解决方案,它处理传输并制定可衡量的响应。建议您专注于使用字符串作为参数的解决方案脚本,并且应该将 $args 变量填充为数组。
string2array 工作台脚本:
#!/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; do
# source the solution to turn $REPLY in $args array
source $1 "${REPLY}"
inspect
done
标准解决方案 - 失败
将字符串转换为以空格分隔的单词数组的解决方案适用于我们上面的第一个示例:
#solution1
args=($@)
不良结果
不幸的是,标准解决方案对引用的多字参数产生了不希望的结果:
$ echo 'arg1 "multi arg 2" arg3' | ./string2array solution1
args=(
[0]="arg1"
[1]="\"multi"
[2]="arg"
[3]="2\""
[4]="arg3"
)
挑战:
使用工作台脚本提供一个解决方案 sn-p,它将为收到的参数生成以下结果。
想要的结果:
$ echo 'arg1 "multi arg 2" arg3' | ./string2array solution-xyz
args=(
[0]="arg1"
[1]="multi arg 2"
[2]="arg3"
)
解决方案应该在各个方面都与标准参数解析兼容。对于提供的解决方案,应通过以下单元测试。如果您能想到单元测试中当前缺少的任何内容,请发表评论,我们可以对其进行更新。
需求的单元测试
更新:测试简化并包括 Johnathan Leffer 测试
#!/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 do that!\" but \"they didn't listen.\""
【问题讨论】:
-
好吧,你没有像
"He said, \"Don't do that!\", but they didn't listen."或'$var'或'$(cmd)'符号这样的参数。 -
必须稍微修改字符串才能成为有效的参数。看看你是否同意...
标签: arrays string bash arguments argument-passing