我正在尝试迭代一个可能是null
字符串或字符串数组的变量。
ZEIT_DEPLOYMENT_ALIASES=null
或者ZEIT_DEPLOYMENT_ALIASES=['domain.sh]
我是 bash 的初学者,我读过bash 迭代文件列表,除非为空但我不明白。
我尝试了两种不同的方法。
的值ZEIT_DEPLOYMENT_ALIASES
实际上来自jq
读取 JSON 的库。
ZEIT_DEPLOYMENT_ALIASES=$(cat now.$CUSTOMER_REF_TO_DEPLOY.staging.json | jq --raw-output '.alias')
方法一
ZEIT_DEPLOYMENT_ALIASES=['test.sh']
# Check if there are no aliases configured
if [ -z "$ZEIT_DEPLOYMENT_ALIASES" ]
then
ZEIT_DEPLOYMENT_ALIASES_COUNT=${#ZEIT_DEPLOYMENT_ALIASES[@]}
echo "$ZEIT_DEPLOYMENT_ALIASES_COUNT alias(es) found. Aliasing them now..."
# For each alias configured, then alias it to the deployed domain
for DEPLOYMENT_ALIAS in "${ZEIT_DEPLOYMENT_ALIASES_COUNT[@]}"
do
echo "npx now alias "$ZEIT_DEPLOYMENT_URL $DEPLOYMENT_ALIAS
npx now alias $ZEIT_DEPLOYMENT_URL $DEPLOYMENT_ALIAS --token $ZEIT_TOKEN || echo "Aliasing failed for '$DEPLOYMENT_ALIAS', but the build will continue regardless."
done
else
# $ZEIT_DEPLOYMENT_ALIASES is null, this happens when it was not defined in the now.json file
echo "There are no more aliases to configure. You can add more aliases from your now.json 'alias' property. See https://vercel.com/docs/configuration?query=alias%20domain#project/alias"
echo "$ZEIT_DEPLOYMENT_ALIASES"
fi
但有了这个,即使ZEIT_DEPLOYMENT_ALIASES=['something']
它没有进入then
条款。
方法2
ZEIT_DEPLOYMENT_ALIASES=['test.sh']
echo "Alias(es) for current project:" $ZEIT_DEPLOYMENT_ALIASES
for DEPLOYMENT_ALIAS in $ZEIT_DEPLOYMENT_ALIASES; do
[ -z "$DEPLOYMENT_ALIAS" ] || continue
echo "npx now alias "$ZEIT_DEPLOYMENT_URL $DEPLOYMENT_ALIAS
npx now alias $ZEIT_DEPLOYMENT_URL $DEPLOYMENT_ALIAS --token $ZEIT_TOKEN || echo "Aliasing failed for '$DEPLOYMENT_ALIAS', but the build will continue regardless."
done
同样,似乎[ -z "$DEPLOYMENT_ALIAS" ]
总是评估为true
。
如果您愿意,这里有一个游乐场:
答案1
给定这个文件:
$ cat test.json
{"alias": ["foo", "bar"], "whatever": "xyzzy"}
至少我的版本jq
给出了这个输出jq --raw-output '.alias[]' < test.json
$ jq --raw-output '.alias[]' < test.json
foo
bar
即条目位于不同的行上,这很重要,因为我们可以使用它来将它们彼此分开。例如,通过将它们读取到带有readarray
. (<(...)
是一个流程替代,它使命令的输出像文件一样可用,因此< <(...)
使其在标准输入中可用。实际上,有点像管道,只不过管道运行子 shell,因此在管道之后读取的值将不可用。)
#!/bin/bash
readarray -t entries < <(jq '.alias[]' < test.json)
if [ "${#entries[@]}" = 0 ]; then
echo empty array...
fi
# this will not do anything if the array is empty
for entry in "${entries[@]}"; do
echo "processing entry $entry..."
done
要处理可能缺失的alias
字段,请使用.alias[]?
injq
代替。但请注意,这会将非数组字符串值(例如{"alias": "foo"}
)处理为空,因此如果有可能,我们需要做其他事情。
另请注意,如果条目包含换行符,--raw-output
将按原样打印它们,因此包含换行符的条目将显示为拆分为多行,就好像它们是多个不同的条目一样。
或者,无需进程替换,因此这应该适用于标准 shell,而不仅仅是 Bash。
#!/bin/sh
jq --raw-output '.alias[]' < json.txt |
(
any=
while IFS= read -r line; do
echo "doing something with '$line'..."
any=1
done
if [ "$any" != 1 ]; then
echo "empty input..."
fi
)
看为什么我的变量在一个“while read”循环中是本地变量,但在另一个看似相似的循环中却不是?至于为什么括号是必要的。
现在,关于你的代码:
ZEIT_DEPLOYMENT_ALIASES=['test.sh']
这会将字符串分配[test.sh]
给变量。这["test.sh"]
与像从 中获取的那样分配字符串不同jq
,因为在这里,shell 会处理您提供的引号。它们不会根据命令替换的输出进行类似的处理。这也是单个标量变量,而不是数组。
if [ -z "$ZEIT_DEPLOYMENT_ALIASES" ]
这测试字符串是否为空字符串,这可能不是您的意思。不管怎样,jq
's.alias
可以给细绳 null
,这与空字符串不同。
${#ZEIT_DEPLOYMENT_ALIASES[@]}
这将永远是1
,因为它不是一个数组。出于同样的原因,
for
循环不会执行您想要的操作。
请注意,Bash 本身并不处理 JSON,如果它从命令替换中获取字符串["foo", "bar"]
,那么它只是一个细绳。您需要自己将其拆分为各个条目......
答案2
这是尝试 #1 的解决方案
由于其null
价值,这很棘手,这与empty
我最初的想法并无不同。
最难的事情是jq
使用以下方法将 JSON 数组转换为 bash 数组:
readarray -t ZEIT_DEPLOYMENT_ALIASES < <(jq --raw-output '.alias[]' < now.$CUSTOMER_REF_TO_DEPLOY.staging.json)
非常感谢https://unix.stackexchange.com/a/615717/60329
ZEIT_DEPLOYMENT_ALIASES_JSON=$(cat now.$CUSTOMER_REF_TO_DEPLOY.staging.json | jq --raw-output '.alias')
echo "Custom aliases: " $ZEIT_DEPLOYMENT_ALIASES_JSON
# Convert the JSON array into a bash array - See https://unix.stackexchange.com/a/615717/60329
readarray -t ZEIT_DEPLOYMENT_ALIASES < <(jq --raw-output '.alias[]' < now.$CUSTOMER_REF_TO_DEPLOY.staging.json)
# Check if there are no aliases configured (it will return "null" in such case, which is not the same as bash "empty")
if [ "$ZEIT_DEPLOYMENT_ALIASES" != null ]
then
ZEIT_DEPLOYMENT_ALIASES_COUNT=${#ZEIT_DEPLOYMENT_ALIASES[@]}
echo "$ZEIT_DEPLOYMENT_ALIASES_COUNT alias(es) found. Aliasing them now..."
# For each alias configured, then assign it to the deployed domain
for DEPLOYMENT_ALIAS in "${ZEIT_DEPLOYMENT_ALIASES[@]}"; do
echo "npx now alias "$ZEIT_DEPLOYMENT_URL $DEPLOYMENT_ALIAS
npx now alias $ZEIT_DEPLOYMENT_URL $DEPLOYMENT_ALIAS --token $ZEIT_TOKEN || echo "Aliasing failed for '$DEPLOYMENT_ALIAS', but the build will continue regardless."
done
else
# $ZEIT_DEPLOYMENT_ALIASES is null, this happens when it was not defined in the now.json file
echo "There are no more aliases to configure. You can add more aliases from your now.json 'alias' property. See https://vercel.com/docs/configuration?query=alias%20domain#project/alias"
echo "$ZEIT_DEPLOYMENT_ALIASES"
fi
谢谢你!