Jam*_*ond 7 bash array shell-script curl readonly
最近,我决定读多一点关于bash的内置插件declare
,local
和readonly
,这使我从切换:
local variable_name
variable_name='value'
readonly variable_name
Run Code Online (Sandbox Code Playgroud)
到:
variable_name='value'
declare -r variable_name
Run Code Online (Sandbox Code Playgroud)
此更改减少了写入的行数并允许我设置一些属性,例如告诉 bash 变量的值是一个整数,这很好。然而,在创建一个用作 cURL 别名的函数时,我注意到如果我使用declare
,数组中的变量永远不会扩展,但使用local
和扩展就好了readonly
。
下面是一个例子:
#!/usr/bin/env bash
set -o errexit -o errtrace -o pipefail -o nounset
IFS=$'\n\t'
curl() {
curl_version="$(command curl --version | awk 'NR==1 {print $2}')"
declare -r curl_version
curl_args=(
--user-agent "curl/${curl_version}"
--silent
--fail
)
command curl "${curl_args[@]}" \
"${@}"
}
curl --url 'https://httpbin.org/get'
Run Code Online (Sandbox Code Playgroud)
因为无论出于何种原因变量都不会扩展,--user-agent
数组的一部分使脚本退出并出现错误,因为据 bash 所知,这是一个未绑定的变量,并且由于set -o nounset
.
几天来我一直试图让它发挥作用,所以我想是时候扔掉毛巾寻求帮助了。任何人都可以指出我正确的方向以了解我做错了什么吗?
编辑:
忘了提及,但如果我在同一行中声明该变量确实会扩展,例如declare -r variable_name
. 问题是,如果我这样做,我会从 ShellCheck 中点击SC2155,因此我尝试在设置值后进行声明。
Sté*_*las 12
和:
Run Code Online (Sandbox Code Playgroud)curl_version="$(command curl --version | awk 'NR==1 {print $2}')" declare -r curl_version
在函数中,您将$curl_version
全局变量设置为某个值,然后创建一个单独的本地和只读变量,该变量最初未设置。
看起来你想要:
# instantiate a new local variable (but in bash it inherits the "export"
# attribute if any of the variable with same name in the parent scope)
local curl_version
# unset to remove that export attribute if any. Though you could
# also change the above to local +x curl_version
unset -v curl_version
# give a value:
curl_version="$(command curl --version | awk 'NR==1 {print $2}')"
# make that local variable read only
local -r curl_version
Run Code Online (Sandbox Code Playgroud)
(这里使用local
而不是declare
更清楚地说明您想要将变量设为本地¹)。
或者同时使用:
local +x -r curl_version="$(command curl --version | awk '{print $2; exit}')"
Run Code Online (Sandbox Code Playgroud)
(尽管正如 shellcheck 所指出的那样,您会丢失管道²的退出状态)。
无论如何,我不会像在 C 中使用的那样在 shell 中使用readonly
/ typeset -r
,const
尤其是在bash
. Shell(除了 ksh93)没有像 C 中那样的静态作用域。在bash
(与zsh
例如相反)中,如果函数在全局作用域中被设为只读,则不能创建函数的局部变量。
例如:
count() {
local n
for (( n = 0; n < $1; n++ )) { echo "$n"; }
}
readonly n=5
count "$n"
Run Code Online (Sandbox Code Playgroud)
可以在 zsh 中工作,但不能在 bash 中工作。如果您只使用local -r
而从不使用可能没问题readonly
。
¹在任何情况下typeset
/ declare
/local
都是一样的bash
,唯一的区别是,如果您尝试使用local
功能之外,它报告错误。typeset -r
and之间的区别readonly
(与typeset -x
and之间相同export
)在于后者如果在函数内调用则不会实例化新变量。
²与了解如何exit
在awk
该版本awk
停止处理第一线后的输入,curl
可以用一个SIGPIPE(在实践中是非常不太可能,因为被杀死curl
将派遣其输出一气呵成,它会适合在管道)和因pipefail
,管道最终可能会以 141 退出状态失败,但local
只要它可以为变量赋值,它本身仍然会成功。
函数的第一行创建了一个全局变量。
curl_version="$(command curl --version | awk 'NR==1 {print $2}')"
Run Code Online (Sandbox Code Playgroud)
函数的第二行创建一个只读的、空的、LOCAL变量
declare -r curl_version
Run Code Online (Sandbox Code Playgroud)
此局部变量覆盖全局变量的值。
请注意以下摘录help declare
:
当在函数中使用时,`declare' 使 NAME 成为本地的,就像 `local' 命令一样。`-g' 选项禁止这种行为。
我会推荐这个:
curl() {
local -r curl_version="$(command curl --version | awk 'NR==1 {print $2}')"
local curl_args=(
--user-agent "curl/${curl_version}"
--silent
--fail
)
command curl "${curl_args[@]}" \
"${@}"
}
Run Code Online (Sandbox Code Playgroud)
要检查变量,请declare -p curl_version curl_args
在命令调用之前添加到函数中。
归档时间: |
|
查看次数: |
409 次 |
最近记录: |