sed / awk или другое: однострочное увеличение числа на 1 с сохранением пробелов - PullRequest
4 голосов
/ 22 апреля 2010

РЕДАКТИРОВАТЬ : Я не знаю заранее, в какой «колонке» будут мои цифры, и я хотел бы иметь одну строку. Очевидно, что 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 (используя область замены с command-on-region команды Emacs *, но это не то же самое) вопрос: этот вопрос конкретно о том, как "сохранить пробелы" при работе с awk / sed / etc.

Ответы [ 5 ]

5 голосов
/ 22 апреля 2010

Вот вариант ответа 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. И встроенные пробелысохранились.

Он разбит на несколько строк, чтобы его было легче читать, но его можно копировать / вставлять.

3 голосов
/ 22 апреля 2010
$ 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
2 голосов
/ 22 апреля 2010

что-то вроде

number=`echo "eh oh 37" | grep -o '[0-9]*'`
sed 's/$number/`expr $number + 1`/'
1 голос
/ 22 апреля 2010

Как насчет:

$ echo "eh oh   37" | awk -F'[ \t]' '{$NF = $NF - 1;} 1'
eh oh   36
0 голосов
/ 02 мая 2014

Решение не сохранит количество десятичных дробей, поэтому, если число равно 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...