shell-正确处理引用的参数

时间:2018-10-31 02:18:54

标签: bash shell arguments

说我有一个bash脚本,如下所示,它的目的是将所有参数连接到命令字符串,然后执行此命令。如您在下面看到的,加入的命令无法成功执行,我认为我没有正确处理带引号的字符串。我想知道为什么以及如何纠正它。

脚本:

$ cat testarg.sh
#!/bin/bash
echo "args number: $#"

args="$@"

cmd=""

#way 1, loop over $@
for arg in $args
do
    echo "arg: $arg"
    cmd="$cmd $arg"
done

ttt=""

#way 2, use shift built-in
while [[ $# -gt 0  ]]
do
    k="$1"
    shift
    echo "k: $k"
    ttt="$ttt $k"
done

echo "args: $args"
echo "cmd: $cmd"
echo "ttt: $ttt"

$ttt

使用curl命令运行脚本的输出(失败):

$ testarg.sh curl -k -X POST -H "Content-Type: application/json" -d '{"username":"admin", "password": "passw0rd"}' "https://localhost:8443/token/generate"
args number: 9
arg: curl
arg: -k
arg: -X
arg: POST
arg: -H
arg: Content-Type:
arg: application/json
arg: -d
arg: {"username":"admin",
arg: "password":
arg: "passw0rd"}
arg: https://localhost:8443/token/generate
k: curl
k: -k
k: -X
k: POST
k: -H
k: Content-Type: application/json
k: -d
k: {"username":"admin", "password": "passw0rd"}
k: https://localhost:8443/token/generate
args: curl -k -X POST -H Content-Type: application/json -d {"username":"admin", "password": "passw0rd"} https://localhost:8443/token/generate
cmd:  curl -k -X POST -H Content-Type: application/json -d {"username":"admin", "password": "passw0rd"} https://localhost:8443/token/generate
ttt:  curl -k -X POST -H Content-Type: application/json -d {"username":"admin", "password": "passw0rd"} https://localhost:8443/token/generate
<html>
<head><title>302 Found</title></head>
<body bgcolor="white">
<center><h1>302 Found</h1></center>
<hr><center>nginx</center>
</body>
</html>
<html>
<head><title>302 Found</title></head>
<body bgcolor="white">
<center><h1>302 Found</h1></center>
<hr><center>nginx</center>
</body>
</html>
curl: (3) [globbing] unmatched close brace/bracket in column 11
{
  "timestamp" : "2018-10-31T02:05:48.333+0000",
  "status" : 415,
  "error" : "Unsupported Media Type",
  "message" : "Content type 'application/octet-stream' not supported",
  "path" : "/token/generate"
}

因此,看来我无法在“ $ @”上循环,然后重新加入它们,它用多个元素拆分了引用的字符串。因此,我使用shift内置程序,将引用的字符串保留下来。

直接运行上面的$ ttt字符串时输出相同(失败):

$ curl -k -X POST -H Content-Type: application/json -d {"username":"admin", "password": "passw0rd"} https://localhost:8443/token/generate
<html>
<head><title>302 Found</title></head>
<body bgcolor="white">
<center><h1>302 Found</h1></center>
<hr><center>nginx</center>
</body>
</html>
<html>
<head><title>302 Found</title></head>
<body bgcolor="white">
<center><h1>302 Found</h1></center>
<hr><center>nginx</center>
</body>
</html>
curl: (3) [globbing] unmatched close brace/bracket in column 9
{
  "timestamp" : "2018-10-31T02:29:24.973+0000",
  "status" : 415,
  "error" : "Unsupported Media Type",
  "message" : "Content type 'application/octet-stream' not supported",
  "path" : "/token/generate"
}

直接运行完全相同的curl命令(成功)时的输出:

$ curl -k -X POST -H "Content-Type: application/json" -d '{"username":"admin", "password": "passw0rd"}' "https://localhost:8443/token/generate"
{
  "token" : "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJhZG1pbiIsInJvbGUiOiJBRE1JTklTVFJBVE9SIiwianRpIjoiYTE0MWZmMTAtZjNlMi00ZDVhLWFjOGUtODE1Y2YzNzYyNzA0IiwiaXNzIjoiaHR0cDovL2libS5jb20iLCJpYXQiOjE1NDA5NTE1NDAsImV4cCI6MTU0MTAzNzk0MH0.plrjsVAPaRSU6K2WnlTCy-6V1iuSK01F6SULH4lELqs"
}

我想加入所有参数的原因是将来我想向另一个传递的curl命令添加标头。例如添加身份验证令牌。

例如,假设用户要运行以下curl命令:

testarg.sh curl -k -X POST -H "Content-Type: application/json" -d '{"key": "value"}' "https://localhost:8443/protected_page"

然后使用testargs.sh,将auth标头添加到curl命令中,最后执行curl命令:

curl -H "Authorization: Bearer <token>" -k -X POST -H "Content-Type: application/json" -d '{"key": "value"}' "https://localhost:8443/protected_page"

谢谢。

2 个答案:

答案 0 :(得分:1)

"$@"复制到常规变量会破坏您在该变量中的所有引用。您想直接循环"$@",或者如果确实确实需要先复制它,则将其复制到数组中。

答案 1 :(得分:1)

args="$@"将所有参数合并为一个:

$ set -- foo 'bar baz'
$ printf '%q\n' "$args"
foo\ bar\ baz

您可以设置args=("$@")

$ args=("$@")
$ printf '%q\n' "${args[@]}"
foo
bar\ baz

甚至更好的是,完全避免引用-for argfor arg in "$@"的语法糖。