如何在Bash中将'4-7'替换为'4,5,6,7'

如何在Bash中将'4-7'替换为'4,5,6,7',bash,macos,eval,ram,brace-expansion,Bash,Macos,Eval,Ram,Brace Expansion,目标 我有一个长字符串s,它表示由逗号和破折号分隔的一系列数字(见下文)。当几个数字紧跟在一起时,两个极端数字被写下来并用破折号隔开。例如,序列4,5,6,7被写成4-7。我的目标是扩展这个字符串,使所有数字都用comas分隔(4-7应该变成4,5,6,7) 我所做的 下面是一个字符串示例 s="4092-4093,4095-4097,4104,4107,4111,4125-4127" 我想首先用{4..7}替换类型4-7的模式(使用sed反向引用) 然后计算字符串以展开大括号 b="$(ev

目标

我有一个长字符串
s
,它表示由逗号和破折号分隔的一系列数字(见下文)。当几个数字紧跟在一起时,两个极端数字被写下来并用破折号隔开。例如,序列
4,5,6,7
被写成
4-7
。我的目标是扩展这个字符串,使所有数字都用comas分隔(
4-7
应该变成
4,5,6,7

我所做的

下面是一个字符串示例

s="4092-4093,4095-4097,4104,4107,4111,4125-4127"
我想首先用
{4..7}
替换类型
4-7
的模式(使用sed反向引用)

然后计算字符串以展开大括号

b="$(eval echo $a)"
然而,当我运行最后一个命令时,扩展是“以阶乘方式”完成的(导致RAM使用量激增)

问题

如何将字符串中的
4-7
类型的模式替换为
4,5,6,7

版本


我使用的是
Mac OS X 10.11.3
,使用的是
终端2.6.1(361.1)

,这是因为你的代码并不像你想象的那样。考虑一下<代码> s=“4092-40934095-4097”< /代码>。在运行
sed
之后,这将导致
a={4092..4093},{4095..4097}
。在运行
eval
后,会导致:

b=4092,4095 4092,4096 4092,4097 4093,4095 4093,4096 4093,4097
我猜你在期待这样的事情:

b=4092,4093,4095,4096,4096

如果您还没有注意到这两个表达式之间的差异,那么实际结果就是两个大括号表达式的所有可能组合。您的实际情况是有更多的组合,从而导致。

这是因为您的代码没有做您显然认为它做的事情。考虑一下<代码> s=“4092-40934095-4097”< /代码>。在运行
sed
之后,这将导致
a={4092..4093},{4095..4097}
。在运行
eval
后,会导致:

b=4092,4095 4092,4096 4092,4097 4093,4095 4093,4096 4093,4097
我猜你在期待这样的事情:

b=4092,4093,4095,4096,4096

如果您还没有注意到这两个表达式之间的差异,那么实际结果就是两个大括号表达式的所有可能组合。您的实际情况是,有更多的组合,因此。

使用GNU awk的答案应该在大输入时表现更好:

#!/usr/bin/env gawk -f
{
    while ( match($0, /([0-9]+)-([0-9]+)/, arr) ) {
        s = arr[1]
        for (i=int(arr[1]) + 1; i<=int(arr[2]); i++) {
            s = s "," i
        }
        gsub(arr[1] "-" arr[2], s)
    }
    print
}

使用GNU awk的答案,在大输入情况下应表现更好:

#!/usr/bin/env gawk -f
{
    while ( match($0, /([0-9]+)-([0-9]+)/, arr) ) {
        s = arr[1]
        for (i=int(arr[1]) + 1; i<=int(arr[2]); i++) {
            s = s "," i
        }
        gsub(arr[1] "-" arr[2], s)
    }
    print
}
救援人员:

echo 4092-4093,4095-4097,4104,4107,4111,4125-4127 \
| perl -lane 's/-/../g;print join ",", eval'
在Perl中,范围是用
运算符而不是破折号编写的。在其上运行会将字符串扩展到实际列表。

Perl来拯救:

echo 4092-4093,4095-4097,4104,4107,4111,4125-4127 \
| perl -lane 's/-/../g;print join ",", eval'


在Perl中,范围是用
运算符而不是破折号编写的。在上面运行会将字符串扩展到实际列表。

最后一个问题是关于为什么;新问题是关于如何处理它。是的,很抱歉。我在发帖后编辑了这个问题,因为我自己也知道了“为什么”。@CharlesDuffy最初问的问题是为什么。新问题应该贴在新问题上。@RossRidge,……这是他们有答案时的规则。编辑时,您的答案尚未发布。最后一个问题是关于为什么;新问题是关于如何处理它。是的,很抱歉。我在发帖后编辑了这个问题,因为我自己也知道了“为什么”。@CharlesDuffy最初问的问题是为什么。新问题应该贴在新问题上。@RossRidge,……这是他们有答案时的规则。编辑时您的答案尚未发布。您是否有
gawk
?我没有,所以我安装了它。现在,我有了
gawk
。你有
gawk
?我没有,所以我安装了它。现在,我有
gawk
@Remi.b,…正在工作。使用awk可能会更快,因为bash的字符串替换函数的长度伸缩性很差——性能可以接受吗?是的,性能可以接受。我的字符串大小是50倍,但我只需要运行一次进程。事实上,我最终找到(并使用)了一个可能不会比你的更快的解决方案。我想对于其他用户来说,我最好等待一个更清晰的答案(最终使用
gawk
)。你觉得怎么样?我正在研究这样一个答案,所以如果你不介意等待的话…:)@Remi.b:修订。当我写这篇文章时,埃德蒙顿从我的肩膀后面看了看,所以我有信心这并不太可怕@现在正在工作。使用awk可能会更快,因为bash的字符串替换函数的长度伸缩性很差——性能可以接受吗?是的,性能可以接受。我的字符串大小是50倍,但我只需要运行一次进程。事实上,我最终找到(并使用)了一个可能不会比你的更快的解决方案。我想对于其他用户来说,我最好等待一个更清晰的答案(最终使用
gawk
)。你觉得怎么样?我正在研究这样一个答案,所以如果你不介意等待的话…:)@Remi.b:修订。当我写这篇文章时,埃德蒙顿从我的肩膀后面看了看,所以我有信心这并不太可怕