bash 变量作为命令:在执行前回显命令并将结果保存到变量
bash variable as a command: echo the command before execution and save the result to a variable
我正在执行一系列 curl
命令:
- 我需要在执行前回显命令。
- 执行命令并将结果保存到bash变量。
- 从执行结果中获取值并使用该值执行下一个 curl。
是这样的:
# -----> step 1 <-----
URL="https://web.example.com:8444/hello.html"
CMD="curl \
--insecure \
--dump-header - \
\"$URL\""
echo $CMD && eval $CMD
OUT="<result of the curl command???>"
# Set-Cookie: JSESSIONID=5D5B29689EFE6987B6B17630E1F228AD; Path=/; Secure; HttpOnly
JSESSIONID=$(echo $OUT | grep JSESSIONID | awk '{ s = ""; for (i = 2; i <= NF; i++) s = s $i " "; print s }' | xargs)
# Location: https://web.example.com:8444/oauth2/authorization/openam
URL=$(echo $OUT | grep Location | awk '{print }')
# -----> step 2 <-----
CMD="curl \
--insecure \
--dump-header - \
--cookie \"$JSESSIONID\" \
\"$URL\""
echo $CMD && eval $CMD
OUT="<result of the curl command???>"
...
# -----> step 3 <-----
...
我只有 step 2
有问题:将 curl
命令的完整结果保存到一个变量中,以便我可以解析它。
我试过很多不同的方法,但没有一个有效:
OUT="eval $CMD"
OUT=$$CMD
OUT=$($CMD)
- ...
我错过了什么?
我想 OUT=$(eval $CMD)
会如你所愿。
简易模式:使用set -x
Bash 有一个内置的特性,xtrace
,它告诉它将每个命令记录到变量 BASH_XTRACEFD
中命名的文件描述符(默认情况下,文件描述符 2 , 标准错误).
#!/bin/bash
set -x
url="https://web.example.com:8444/hello.html"
output=$(curl \
--insecure \
--dump-header - \
"$url")
echo "Output of curl follows:"
echo "$output"
...将提供以下形式的日志:
+ url=https://web.example.com:8444/hello.html
++ curl --insecure --dump-header - https://web.example.com:8444/hello.html
+ output=Whatever
+ echo 'Output of curl follows:'
+ echo Whatever
...其中+
是基于变量PS4
的内容,可以对其进行修改以获得更多信息。 (我经常使用并建议 PS4=':${BASH_SOURCE}:$LINENO+'
将源文件名和行号放在每个记录的行中)。
手工制作
如果不行,你可以写一个函数。
log_and_run() {
{ printf '%q ' "$@"; echo; } >&2
"$@"
}
output=$(log_and_run curl --insecure --dump-header - "$url")
...会将您的 curl 命令行写入 stderr,然后再将其输出存储在 $output
中。请注意,在编写该输出时需要使用引号:echo "$output"
,而不是 echo $output
.
对于非常基本的命令,OUT=$($CMD)
应该可以。问题在于,存储在变量中的字符串与直接输入的字符串的处理方式不同。例如,echo "a"
打印 a
,但 var='"a"'; echo $a
打印 "a"
(注意引号)。由于这个和其他原因,您不应将命令存储在变量中。
在bash中,您可以改用数组。顺便说一句:常规变量的命名约定不是全部大写,因为这样的名称可能会意外地与特殊变量发生冲突。此外,您可能可以大大简化您的 grep | awk | xargs
.
url="https://web.example.com:8444/hello.html"
cmd=(curl --insecure --dump-header - "$url")
printf '%q ' "${cmd[@]}"; echo
out=$("${cmd[@]}")
# Set-Cookie: JSESSIONID=5D5B29689EFE6987B6B17630E1F228AD; Path=/; Secure; HttpOnly
jsessionid=$(awk '{=""; printf "%s%s", d, substr([=10=],2); d=FS}' <<< "$out")
# Location: https://web.example.com:8444/oauth2/authorization/openam
url=$(awk '/Location/ {print }' <<< "$out")
# -----> step 2 <-----
cmd=(curl --insecure --dump-header - --cookie "$jsessionid" "$url")
printf '%q ' "${cmd[@]}"; echo
out=$("${cmd[@]}")
# -----> step 3 <-----
...
如果您的步骤比这更多,请将重复部分包装成 。
我正在执行一系列 curl
命令:
- 我需要在执行前回显命令。
- 执行命令并将结果保存到bash变量。
- 从执行结果中获取值并使用该值执行下一个 curl。
是这样的:
# -----> step 1 <-----
URL="https://web.example.com:8444/hello.html"
CMD="curl \
--insecure \
--dump-header - \
\"$URL\""
echo $CMD && eval $CMD
OUT="<result of the curl command???>"
# Set-Cookie: JSESSIONID=5D5B29689EFE6987B6B17630E1F228AD; Path=/; Secure; HttpOnly
JSESSIONID=$(echo $OUT | grep JSESSIONID | awk '{ s = ""; for (i = 2; i <= NF; i++) s = s $i " "; print s }' | xargs)
# Location: https://web.example.com:8444/oauth2/authorization/openam
URL=$(echo $OUT | grep Location | awk '{print }')
# -----> step 2 <-----
CMD="curl \
--insecure \
--dump-header - \
--cookie \"$JSESSIONID\" \
\"$URL\""
echo $CMD && eval $CMD
OUT="<result of the curl command???>"
...
# -----> step 3 <-----
...
我只有 step 2
有问题:将 curl
命令的完整结果保存到一个变量中,以便我可以解析它。
我试过很多不同的方法,但没有一个有效:
OUT="eval $CMD"
OUT=$$CMD
OUT=$($CMD)
- ...
我错过了什么?
我想 OUT=$(eval $CMD)
会如你所愿。
简易模式:使用set -x
Bash 有一个内置的特性,xtrace
,它告诉它将每个命令记录到变量 BASH_XTRACEFD
中命名的文件描述符(默认情况下,文件描述符 2 , 标准错误).
#!/bin/bash
set -x
url="https://web.example.com:8444/hello.html"
output=$(curl \
--insecure \
--dump-header - \
"$url")
echo "Output of curl follows:"
echo "$output"
...将提供以下形式的日志:
+ url=https://web.example.com:8444/hello.html
++ curl --insecure --dump-header - https://web.example.com:8444/hello.html
+ output=Whatever
+ echo 'Output of curl follows:'
+ echo Whatever
...其中+
是基于变量PS4
的内容,可以对其进行修改以获得更多信息。 (我经常使用并建议 PS4=':${BASH_SOURCE}:$LINENO+'
将源文件名和行号放在每个记录的行中)。
手工制作
如果不行,你可以写一个函数。
log_and_run() {
{ printf '%q ' "$@"; echo; } >&2
"$@"
}
output=$(log_and_run curl --insecure --dump-header - "$url")
...会将您的 curl 命令行写入 stderr,然后再将其输出存储在 $output
中。请注意,在编写该输出时需要使用引号:echo "$output"
,而不是 echo $output
.
对于非常基本的命令,OUT=$($CMD)
应该可以。问题在于,存储在变量中的字符串与直接输入的字符串的处理方式不同。例如,echo "a"
打印 a
,但 var='"a"'; echo $a
打印 "a"
(注意引号)。由于这个和其他原因,您不应将命令存储在变量中。
在bash中,您可以改用数组。顺便说一句:常规变量的命名约定不是全部大写,因为这样的名称可能会意外地与特殊变量发生冲突。此外,您可能可以大大简化您的 grep | awk | xargs
.
url="https://web.example.com:8444/hello.html"
cmd=(curl --insecure --dump-header - "$url")
printf '%q ' "${cmd[@]}"; echo
out=$("${cmd[@]}")
# Set-Cookie: JSESSIONID=5D5B29689EFE6987B6B17630E1F228AD; Path=/; Secure; HttpOnly
jsessionid=$(awk '{=""; printf "%s%s", d, substr([=10=],2); d=FS}' <<< "$out")
# Location: https://web.example.com:8444/oauth2/authorization/openam
url=$(awk '/Location/ {print }' <<< "$out")
# -----> step 2 <-----
cmd=(curl --insecure --dump-header - --cookie "$jsessionid" "$url")
printf '%q ' "${cmd[@]}"; echo
out=$("${cmd[@]}")
# -----> step 3 <-----
...
如果您的步骤比这更多,请将重复部分包装成