Любая версия Awk
awk -v ref=30.0 '{ print $1, $2, $3, ($3 < ref) ? ref - $3 : $3 - ref }' |
sort -k4,4n |
awk '{ print $1, $2, $3 }'
Добавьте расстояние от контрольного возраста в качестве дополнительного столбца, отсортируйте его, удалите. Вы можете использовать cut
для операции удаления, если хотите. Если вы используете GNU Awk, вы можете сделать все это в awk
. Есть способы сохранить интервал, если это важно для вас.
Вы можете написать все это в одну строку, если вы настаиваете; Это ваш выбор.
Многофункциональное устройство с использованием GNU Awk
Проверка руководства GNU Awk показывает, что встроенной функции abs()
нет, что немного удивительно GNU Awk имеет функции asort()
и asorti()
, которые можно использовать для внутренней сортировки данных, что позволяет коду использовать один вызов awk
и никаких вызовов sort
команда. Это также сохраняет интервал в исходных данных.
Этот вариант использует идею «квадрата расстояния», предложенную zhihao_li в их ответе .
gawk -v ref=48.0 '
function comp_idx(i1, v1, i2, v2) {
if (i1+0 < i2+0) return -1; else if (i1+0 > i2+0) return +1; else return 0;
}
{ data[($3-ref)^2] = $0 }
END {
n = asorti(data, results, "comp_idx")
for (i = 1; i <= n; i++) print data[results[i]]
}' "$@"
Операции +0
в функции comp_idx
необходимы, чтобы awk
обрабатывал значения индекса как числа, а не как строки. Без них порядок сортировки основывался на лексикографическом (не числовом c) порядке квадратов расстояний. Если важна одна строка, вы можете написать это все в одной строке, но вам также понадобится добавить точку с запятой. Я не рекомендую это.
Вы могли бы преобразовать код в более полный сценарий оболочки, который принимает значение age в качестве аргумента, передаваемого Awk (механизм -v ref=30.0
). Это сложнее, чем сложнее. В его нынешнем виде он обрабатывает только те файлы, которые ему даны, или стандартный ввод, если файлы не передаются.
С примерами данных для эталонного возраста 48.0:
name4 F 55.0
name2 M 31.5
name1 M 73.2
name3 F 20.3
Измените базовый возраст с 48,0 до 30,0, как в вопросе, и в результате получите:
name2 M 31.5
name3 F 20.3
name4 F 55.0
name1 M 73.2