awk присваивать сразу нескольким переменным

9

Я пытаюсь извлечь два числовых значения из строки и назначить их переменным с помощью awk( gawkэто то, что я использую специально). Я хочу извлечь старшие и младшие номера версий из строки версии tmux в awkпеременные, например:

  • вход tmux 2.8:; maj == 2а такжеmin == 8
  • вход tmux 1.9a:; maj == 1а такжеmin == 9
  • вход tmux 2.10:; maj == 2а такжеmin == 10

Предполагая, что мой вклад поступил от tmux -Vstdin, в настоящее время у меня есть следующее:

tmux -V | awk '{
                  maj = +gensub(/([0-9]+)\..*/, "\\1", "g", $2);
                  min = +gensub(/.*\.([0-9]+).*/, "\\1", "g", $2);
                  # ...do something with maj and min...
               }'

Это работает, но, как знают многие пользователи tmux, использование if-shellв .tmux.confфайле (где я надеюсь использовать этот материал) может легко привести к очень длинным строкам в файле конфигурации, поэтому мне интересно, есть ли способ объединить эти две переменные присваивания в одном операторе для экономии места ... или любой другой способ извлечь эти две переменные из ввода и сэкономить место.

Я думаю о чем-то вроде:

awk '{ maj, min = +gensub(/([0-9]+)\.([0-9]+).*/, "\\1 \\2", "g", $2); }'

... вроде как в Python, но этот конкретный синтаксис не существует в awk. Есть ли что-нибудь еще, что возможно?

Обратите внимание, что читаемость на самом деле не проблема, просто длина.

villapx
источник

Ответы:

9

Обратите внимание, что gensubэто gawkрасширение, оно не будет работать с любой другой awkреализацией. Также обратите внимание, что +унарный оператор не вызывает числовое преобразование во всех awkреализациях, использование + 0более переносимо.

Здесь вы можете сделать:

tmux -V | awk -F '[ .]' '{maj = $2+0; min = $3+0; print maj, min}'

Если вы не возражаете против использования awkрасширений GNU , вы также можете сделать:

tmux -V | awk -v FPAT='[0-9]+' '{maj = $1; min = $2; print maj, min}'
Стефан Шазелас
источник
Спасибо за дополнительные пояснения по совместимости!
Villapx
13

Поскольку вы используете GNU awk, вы можете использовать 3-аргументную форму match()для хранения нескольких групп захвата:

awk '
    match($0, /([0-9]+)\.([0-9]+)/, m) {maj=m[1]; min=m[2]; print maj, min}
' <<END
tmux 2.8
tmux 1.9a
tmux 2.10
END
2 8
1 9
2 10

https://www.gnu.org/software/gawk/manual/html_node/String-Functions.html

Гленн Джекман
источник
5

Вы можете разделить версию на массив:

awk '{ split($2, ver, /[.a-z]/) }'

тогда используйте ver[1]вместо maj, ver[2]вместо min.

Добавление a-zв разделитель удаляет любую строчную букву из номера версии. (Другие решения здесь лучше, так как они явно извлекают числа.)

Стивен Китт
источник
3

Другой пользователь опубликовал этот ответ, и позже он был удален. Я думал, что это было полезно:

Используя split()функцию, разбейте строку версии на массив ver, затем получите доступ ver[1]и ver[2]вместо majи min, соответственно (или просто сохраните значения в этих переменных):

tmux -V | awk '{ split($2, ver, /[.a-z]/); print ver[1], ver[2] }'

Плюс здесь в том, что split() это не gawkрасширение (хотя его необязательный четвертый аргумент sepsесть).

villapx
источник
+1 но зачем использовать /[.a-z]/в качестве третьего (разделение полей) аргумент splitстроковой функции, а не просто "."?
Cbhihe
2
@Cbhihe смотрите объяснение в моем ответе (который я восстановил, так как villapx считает его полезным, спасибо villapx!).
Стивен Китт