sed/awk 或其他:一行将数字增加 1 并保持空格字符

发布于 2024-08-29 18:00:18 字数 1072 浏览 9 评论 0原文

编辑:我事先不知道我的数字将在哪一“列”,我想要一句台词。显然 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]\)/.../' 

Can I do maths from sed using a reference to thematchingdigits and have the output notmodify the number of spacecharacter?

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

EDIT: I don't know in advance at which "column" my digits are going to be and I'd like to have a one-liner. Apparently sed doesn't do arithmetic, so maybe a one-liner solution based on awk?

I've got a string: (notice the spacing)

eh oh    37

and I want it to become:

eh oh    36

(so I want to keep the spacing)

Using awk I don't find how to do it, so far I have:

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

But this gives:

eh oh 36

(the spacing characters where lost, because the field separator is ' ')

Is there a way to ask awk something like "print the output using the exact same field separators as the input had"?

Then I tried yet something else, using awk's sub(..,..) method:

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

but no cigar yet: I don't know how to reference the regexp and do arithmetic on it in the second argument (which I left with '...' for now).

Then I tried with sed, but got stuck after this:

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

Can I do arithmetic from sed using a reference to the matching digits and have the output not modify the number of spacing characters?

Note that it's related to my question concerning Emacs and how to apply this to some (big) Emacs region (using a replace region with Emacs's shell-command-on-region) but it's not an identical question: this one is specifically about how to "keep spaces" when working with awk/sed/etc.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

心病无药医 2024-09-05 18:00:19

这是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。嵌入的空格被保留。

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

Here is a variation on ghostdog74's answer that does not require the number to be anchored at the end of the string. This is accomplished using match instead of relying on the number to be in a particular position.

This will replace the first number with its value minus one:

$ 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

Using gsub there instead of sub would replace both the "37" and the "22" with "36". If there's only one number on the line, it doesn't matter which you use. By doing it this way, though, it will handle numbers with trailing whitespace plus other non-numeric characters that may be there (after some whitespace).

If you have gawk, you can use gensub like this to pick out an arbitrary number within the string (just set the value of 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

The second (which=2) number went from 22 to 21. And the embedded spaces are preserved.

It's broken out on multiple lines to make it easier to read, but it's copy/pastable.

一个人的夜不怕黑 2024-09-05 18:00:19
$ echo "eh oh    37" | awk '{n=$NF+1; gsub(/[0-9]+$/,n) }1'
eh oh    38

或者

$ echo "eh oh    37" | awk '{n=$NF+1; gsub(/..$/,n) }1'
eh oh    38
$ echo "eh oh    37" | awk '{n=$NF+1; gsub(/[0-9]+$/,n) }1'
eh oh    38

or

$ echo "eh oh    37" | awk '{n=$NF+1; gsub(/..$/,n) }1'
eh oh    38
灯角 2024-09-05 18:00:19

类似的东西

number=`echo "eh oh 37" | grep -o '[0-9]*'`
sed 's/$number/`expr $number + 1`/'

something like

number=`echo "eh oh 37" | grep -o '[0-9]*'`
sed 's/$number/`expr $number + 1`/'
孤星 2024-09-05 18:00:19

怎么样:

$ echo "eh oh   37" | awk -F'[ \t]' '{$NF = $NF - 1;} 1'
eh oh   36

How about:

$ echo "eh oh   37" | awk -F'[ \t]' '{$NF = $NF - 1;} 1'
eh oh   36
孤单情人 2024-09-05 18:00:19

该解决方案不会保留小数位数,因此如果数字是 10,那么结果是 9,即使有人想要 09。

我没有编写尽可能短的代码,它应该保持可读

这里我构造了 printf使用 RLENGTH 的模式,使其变为 %02d (2 是匹配模式的长度)

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

The solution will not preserve the number of decimals, so if the number is 10, then the result is 9, even if one would like to have 09.

I did not write the shortest possible code, it should stay readable

Here I construct the printf pattern using RLENGTH so it becomes %02d (2 being the length of the matched pattern)

$ echo "eh oh    10      aaa     22    bb" |
    awk '{n = substr($0, match($0, /[0-9]+/), RLENGTH)-1 ; 
          nn=sprintf("%0" RLENGTH "d", n)
          sub(/[0-9]+/, nn);
          print 
         }'
eh oh    09      aaa     22    bb
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文