【问题标题】:Create sequence from literal variable inputs [duplicate]从文字变量输入创建序列[重复]
【发布时间】:2021-10-05 12:29:28
【问题描述】:

我正在尝试按如下方式创建序列:

startDay=1
endDay=2
dayRange="{$startDay..$endDay}"
echo \[\"$dayRange\",\"{00..02}\"\]

输出是:

["{1..2}","00"] ["{1..2}","01"] ["{1..2}","02"]

直接指定序列{00..02}时,会自动创建"00", "01", "02",但不理解dayRange变量。 我期望它返回的是:

["1","00"] ["1","01"] ["1","02"] ["2","00"] ["2","01"] ["2","02"] 

不知道我错过了什么。 请指教。

【问题讨论】:

  • 大括号扩展发生在之前参数扩展。当$startDay$endDay 被替换为实际值时,{1..2} 样式的扩展将不再运行。
  • 虽然eval 有一些丑陋的黑客攻击,但理智/可靠/稳健的事情是简单地不这样做;使用for 循环遍历要处理的数字范围。有关示例,请参见 ideone.com/TZoJxp
  • 顺便说一句——请参阅BashPitfalls #33中有关此问题的讨论
  • 我明白了,谢谢@CharlesDuffy

标签: linux bash shell brace-expansion


【解决方案1】:

第一个想法是一个简单的嵌套for 循环:

startDay=1
endDay=2

pfx=
out=

for ((i=startDay; i<=endDay; i++))
do
    for j in {00..02}
    do
         out+="${pfx}[\"${i}\",\"${j}\"]"
         pfx=" "
    done
done

echo "${out}"

这会生成:

["1","00"] ["1","01"] ["1","02"] ["2","00"] ["2","01"] ["2","02"]

编码少一点,速度快一点,它使用 OP 的 echo ... {00..02} 来消除 for 循环之一:

注意:这消除了我在之前的编辑中调用的子进程$(echo ...)

startDay=1
endDay=2

for ((i=startDay; i<=endDay; i++))
do
    echo -n "[\""${i}"\",\""{00..02}"\"]"
    echo -n " "
done

echo ""

这也会产生:

["1","00"] ["1","01"] ["1","02"] ["2","00"] ["2","01"] ["2","02"]

这是一个awk 的想法:

awk -v start=$"${startDay}" -v end="${endDay}" '
BEGIN {
    pfx=""
    out=""

    for (i=start; i<=end; i++)
        for (j=0; j<=2; j++) {
             out=out pfx "[\"" i "\",\"" sprintf("%02d", j) "\"]"
             pfx=" "
        }
    print out
}'

这也会产生:

["1","00"] ["1","01"] ["1","02"] ["2","00"] ["2","01"] ["2","02"]

由于取消了较早的子进程 $(echo ...),前 2 个解决方案采用个位数毫秒计时,而 awk 解决方案采用低两位数毫秒计时。

随着天数(和/或序列大小)的增加,前 2 个解决方案开始花费更长的时间(嵌套的 for 循环远远落后),而 awk 解决方案往往保持相同的速度。

对于非常大的增长(天数和/或序列大小),我预计 awk 会接近并最终占据领先地位。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-09
    • 2021-08-17
    • 1970-01-01
    • 1970-01-01
    • 2019-02-26
    相关资源
    最近更新 更多