编辑:我不知道我的数字将在哪个“列”,我想有一个单线。显然sed不执行算术运算,所以也许是基于awk的单线解决方案?

我有一个字符串:(注意间距)

eh oh    37


我希望它成为:

eh oh    36


(所以我想保持间距)

使用awk我找不到方法,到目前为止,我有:

echo "eh oh   37" | awk '$3>=0&&$3<=99 {$3--} {print}'


但这给出了:

eh oh 36


(丢失的空格字符,因为字段分隔符为'')

有没有办法问awk之类的东西“使用与输入完全相同的字段分隔符打印输出”?

然后,我尝试使用awk的sub(..,..)方法进行其他操作:

' sub(/[0-9][0-9]/, ...) {print}'


但还没有雪茄:我不知道如何引用正则表达式并在第二个参数中对其进行算术运算(现在我留下了“ ...”)。

然后我尝试使用sed,但是在此之后被卡住了:

echo "eh oh   37" | sed -e 's/\([0-9][0-9]\)/.../'


我可以使用对匹配数字的引用从sed进行算术运算,并且输出不修改空格字符的数量吗?

请注意,这与我有关Emacs的问题有关,以及如何将其应用于某些(大)Emacs区域(使用带有Emacs的shell-command-on-region的替换区域),但这不是一个完全相同的问题:这个问题专门针对如何使用awk / sed / etc时“保留空间”。

最佳答案

这是对ghostdog74的回答的一种变体,它不需要将数字固定在字符串的末尾。这是使用match而不是依靠数字位于特定位置来完成的。

这会将第一个数字替换为其值减一:

$ echo "eh oh    37      aaa     22    bb" | awk '{n = substr($0, match($0, /[0-9]+/), RLENGTH) - 1; sub(/[0-9]+/, n); print }'
eh oh    36      aaa     22    bb


在此处使用gsub而不是sub会将“ 37”和“ 22”都替换为“ 36”。如果线路上只有一个数字,则使用哪个都无所谓。但是,通过这种方式,它将处理带有尾随空格的数字以及可能存在的其他非数字字符(在某些空格之后)。

如果有gawk,则可以使用gensub这样在字符串中挑选一个任意数字(只需设置which的值):

$ echo "eh oh    37      aaa     22    bb    19" |
    awk -v which=2 'BEGIN { regex = "([0-9]+)\\>[^0-9]*";
        for (i = 1; i < which; i++) {regex = regex"([0-9]+)\\>[^0-9]*"}}
        { match($0, regex, a);
        n = a[which] - 1;                    # do the math
        print gensub(/[0-9]+/, n, which) }'
eh oh    37      aaa     21    bb    19


第二个(which=2)数字从22到21。保留了嵌入的空间。

为了便于阅读,它分成多行,但是可以复制/粘贴。

10-05 20:48
查看更多