awk - преобразование отрицательных чисел в положительные и наоборот - PullRequest
1 голос
/ 24 марта 2012

У меня есть файл со структурой, подобной этой:

[05:58:10 08.12.1990] 125.441
[05:58:21 08.12.1990] -2.4158
...

Где все, кроме последнего столбца, является своего рода временным кодом (разным для каждого файла), и мне нужно преобразовать последнее число в его противоположность, например:

[05:58:10 08.12.1990] -125.441
[05:58:21 08.12.1990] 2.4158
...

Я пробовал это с awk, но так как мои знания awk довольно скудны, я не совсем достиг этого. Сначала я попытался добавить отрицательные числа с этим:

awk '{$NF=" "; NF--; printf $0; NF++; if ($NF ~ /^[0-9].*/){printf "-"; print $NF}}'

но так как я выбрасываю последний столбец с помощью NF--, я не могу получить его обратно с помощью NF ++.

Любая помощь с этим будет оценена. Спасибо.

Ответы [ 5 ]

5 голосов
/ 24 марта 2012

Попробуйте:

awk '{$NF *= -1; print}'
2 голосов
/ 24 марта 2012

как насчет:

awk '  { if( $NF ~ /^-/ ){sub(/-/, "", $NF); print $0;} 
         else {sub(/^[1-9]*.[1-9]*/,"-"$NF,$NF); print $0}  } '


$ cat data 
[05:58:10 08.12.1990] 125.441
[05:58:21 08.12.1990] -2.4158
$ cat data | awk '  { if( $NF ~ /^-/ ){sub(/-/, "", $NF); print $0;} else {sub(/^[1-9]*.[1-9]*/,"-"$NF,$NF); print $0} }'
[05:58:10 08.12.1990] -125.441
[05:58:21 08.12.1990] 2.4158

редактировать: как предложил Уильям Пурсселл, улучшенная версия этого сценария:

cat data | awk '  { if( $NF ~ /^-/ ){sub(/-/, "", $NF); print $0;} 
         else { $NF="-"$NF; print $0}} '
[05:58:10 08.12.1990] -125.441
[05:58:21 08.12.1990] 2.4158
[05:59:30 08.13.2000] -0.94630008768741448848
1 голос
/ 24 марта 2012

Это может работать для вас:

sed 's/ \([0-9.]*\)$/ -\1/;t;s/\(.*\)-/\1/' file
[05:58:10 08.12.1990] -125.441
[05:58:21 08.12.1990] 2.4158

По сути:

  • Если последнее поле отделено пробелом, добавьте -
  • В противном случае уберите последний минус.
0 голосов
/ 25 марта 2012

http://www.nongnu.org/txr

$ txr -c '@(collect)
[@date] @{sign /-?/}@num
@(output)                                                         
[@date] @(if (equal sign "") "-" "")@num   
@(end)   
@(end)' < data.txt
[05:58:10 08.12.1990] 125.441
[05:58:21 08.12.1990] -2.4158
[05:59:30 08.13.2000] 0.94630008768741448848

Это более надежно, чем хакерские решения, которые слепо переворачивают знак минус за столбцом, потому что мы выполняем некоторое сопоставление с образцом того, как выглядят данные (и мы можем увеличить количество деталей, если необходимо).

Но @(collect) пропускает вещи, которые не совпадают. Одна вещь, которую мы можем сделать, это выбросить исключение, если есть какая-то странная строка:

$ txr -c '@(collect)
@(cases)
[@date] @{sign /-?/}@num
@(or)                                      
@(throw error "invalid data")
@(end)   
@(output)
[@date] @(if (equal sign "") "-" "")@num
@(end)
@(end)' < data.txt
0 голосов
/ 24 марта 2012

Использование sed:

Содержимое script.sed:

## Try to remove the negative sign.
s/\(\] \+\)-\(.*\)$/\1\2/

## If last substitution succeed, goto label 'a'.
ta

## If last substitution failed, there was not negative sign, so
## it is a positive number, I will have to add the sign just 
## before it.
s/\] \+/&-/

## Label 'a' at end of script. Here print line and read next one.
:a

Содержимое infile:

[05:58:10 08.12.1990] 125.441
[05:58:21 08.12.1990] -2.4158

Выполнить как:

sed -f script.sed infile

И результат:

[05:58:10 08.12.1990] -125.441                                                                                                                                                                                                               
[05:58:21 08.12.1990] 2.4158
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...