Как использовать цикл bash for для awk для печати строки FPAT, найденной в переменной в кавычках

Я не могу определить правильный FPAT для получения каждого значения, разделенного запятыми. Использование bash в Debian 12.5... У меня есть файл PING.cfg с содержимым:

NODE01 = "router,10.0.0.1,5"
NODE02 = "dns1,68.6.16.30,35"
NODE03 = "dns2,1.1.1.1,35"

Они используются как переменные, полученные в нескольких сценариях. Я хочу, чтобы сценарий присваивал каждое из значений, разделенных запятыми, переменной в цикле for, может быть, что-то вроде этого:

for n in `grep NODE PING.cfg`
        do
        NODENAME=$(echo "$n" | awk -v FPAT='"[^"]+"' -F',' '{ print $1 }')
        HOSTIP=$(echo "$n" | awk -v FPAT='"[^"]+"' -F',' '{ print $2 }')
        echo "NODE is $NODENAME and HOSTIP is $HOSTIP"
done

Но awk, похоже, не читает кавычки с моим шаблоном FPAT, вывод для $1 включает всю переменную:

NODE is NODE01 = "router and HOSTIP is 10.0.0.1

Попробовал FPAT указать котировки.

Использовать одновременно FPAT и -F не имеет смысла. FPAT переопределяет -F.

Barmar 06.09.2024 00:59

Вы уверены, что используете GNU awk? I FPAT — это расширение GNU.

Barmar 06.09.2024 01:02

Однако как вы ожидаете, что ваш код будет работать с FPAT? Узор соответствует всей "dns1,68.6.16.30,35" части линии. В каждой строке только один из них, так как же вы ожидаете, что $1 и $2 разделят хост и IP?

Barmar 06.09.2024 01:07

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

Barmar 06.09.2024 01:08

GNU Awk 3.1.5 и, надеюсь, mawk 1.3.4

SmplJohn 06.09.2024 01:09

Оба они устарели буквально лет на 20, и ни один из них не поддерживает FPAT (представленный в gawk 4.0). Можете ли вы обновить свою версию GNU awk? В настоящее время мы работаем над версией 5.3.0, которая содержит множество новых функций и исправлений ошибок.

Ed Morton 06.09.2024 01:13

@Allan Wind В файле есть еще какое-то случайное содержимое, помимо того, что показано, которое я хочу игнорировать в вводимых мной переменных. Не знаю, как смешать это при чтении всего файла.

SmplJohn 06.09.2024 01:14

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

Ed Morton 06.09.2024 01:19

Возможно, вместо этого обновите этот файл конфигурации, чтобы использовать формат, который просто и естественно использовать в Bash и Awk. Исправление других скриптов, которые уже используют этот файл, является разовой задачей и, возможно, также упростит их.

tripleee 06.09.2024 06:38
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
9
50
6
Перейти к ответу Данный вопрос помечен как решенный

Ответы 6

Я не думаю, что вы используете версию awk, которая поддерживает FPAT. Но даже если бы это было так, это не сделало бы того, что вы, кажется, ожидаете.

Вместо этого начните с использования кавычек в качестве разделителей полей. Тогда строка dns1,68.6.16.30,35 будет полем 2. Затем вы можете использовать split(), чтобы разделить ее на разделители-запятые.

NODENAME=$(echo "$n" | awk -F'"' '{ split($2, a, /,/); print a[1] }')
HOSTIP=$(echo "$n" | awk -F'"' '{ split($2, a, /,/); print a[2] }')

Это решение не требует каких-либо расширений GNU, все это функции POSIX.

Портативность предпочтительна, поэтому ваше мнение о версии awk принято к сведению. Я готов переформатировать файл, но это многоцелевой файл, который мне также нужно использовать в других сценариях, чтобы использовать их в качестве переменных, поэтому цитирование каждого отдельного поля может испортить ситуацию. Моя цель — иметь возможность получать dns1 как одну переменную, а IP-адрес — как другую переменную.

SmplJohn 06.09.2024 01:19

Я никогда не говорил ничего, что предлагало бы переформатировать файл.

Barmar 06.09.2024 01:21

Я обновил ответ, чтобы показать, как назначать переменные оболочки в вашем скрипте, используя мою технику, вместо того, чтобы выполнять весь цикл в awk.

Barmar 06.09.2024 01:24
Ответ принят как подходящий

Предполагая, что вам по какой-то причине нужны эти значения внутри цикла оболочки, это может быть то, что вам нужно, используя любой awk:

$ cat tst.sh
#!/usr/bin/env bash

while read -r nodename hostip rest; do
    printf 'nodename is %s and hostip is %s\n' "$nodename" "$hostip"
done < <(awk -F'[",]' '/^NODE/{print $2, $3}' PING.cfg)

$ ./tst.sh
nodename is router and hostip is 10.0.0.1
nodename is dns1 and hostip is 68.6.16.30
nodename is dns2 and hostip is 1.1.1.1

Я использую имена переменных в нижнем регистре по причинам, описанным в разделе Правильная заглавная буква переменных Bash и сценария оболочки.

Спасибо, Эд, это очень ясный пример, и он делает именно то, что мне нужно.

SmplJohn 06.09.2024 01:24

Поскольку вы уже выполняете это через скрипт, просто используйте read для анализа каждой строки:

while IFS=, read NODE HOSTIP _
do
    echo "NODE is ${NODE/*\"/} and HOSTIP is $HOSTIP"
done < PING.cfg

и пример запуска:

NODE is router and HOSTIP is 10.0.0.1
NODE is dns1 and HOSTIP is 68.6.16.30
NODE is dns2 and HOSTIP is 1.1.1.1

Поскольку bash помечен, вы также можете использовать регулярные выражения с группами захвата, доступ к которым можно получить через массив ${BASH_REMATCH[@]}. Хорошо составленное регулярное выражение можно использовать даже для рассмотрения только строк, содержащих NODE, заменяя первоначальный grep фильтр:

while read -r line; do
  [[ "$line" =~ ^(NODE[0-9]+)=\"([0-9a-z]+),([0-9.]+),([0-9]+)\"$ ]] &&
  # BASH_REMATCH ╰────[1]───╯   ╰───[2]───╯ ╰──[3]──╯ ╰──[4]─╯
  echo "NODE is ${BASH_REMATCH[2]} and HOSTIP is ${BASH_REMATCH[3]}"
done < PING.cfg
NODE is router and HOSTIP is 10.0.0.1
NODE is dns1 and HOSTIP is 68.6.16.30
NODE is dns2 and HOSTIP is 1.1.1.1

что-то вроде..., мои два бита..

awk -V
GNU Awk 5.0.1, API: 2.0 (GNU MPFR 4.0.2, GNU MP 6.2.0)
Copyright (C) 1989, 1991-2019 Free Software Foundation.

# using poster's supplied input ...
awk -F'"' '{split($2,bits,","); print "NODE is " bits[1] " and HOSTIP is " bits[2]}' < PING.cfg 
NODE is router and HOSTIP is 10.0.0.1
NODE is dns1 and HOSTIP is 68.6.16.30
NODE is dns2 and HOSTIP is 1.1.1.1

Они используются как переменные, полученные из нескольких скриптов.

Если файл уже исходный (или его поиск не будет проблемой), вы можете получить доступ к переменным, начинающимся с NODE, используя расширение параметра Bash${!prefix@}:

. PING.cfg

for n in "${!NODE@}"; do readarray -td, vals <<< "${!n}"
  echo "NODE is ${vals[0]} and HOSTIP is ${vals[1]}"
done

# or

for n in "${!NODE@}"; do IFS=, read -r node hostip value <<< "${!n}"
  echo "NODE is $node and HOSTIP is $hostip"
done

# or

for n in "${!NODE@}"; do printf "NODE is %s and HOSTIP is %s\n" \
  "$(cut -d, -f1 <<< "${!n}")" "$(cut -d, -f2 <<< "${!n}")"
done
NODE is router and HOSTIP is 10.0.0.1
NODE is dns1 and HOSTIP is 68.6.16.30
NODE is dns2 and HOSTIP is 1.1.1.1

Другие вопросы по теме

Похожие вопросы

Bash printf не работает для чисел с плавающей запятой
Bash с использованием сценария Expect выдает ошибку при вызове ssh
Почему моя программа, запущенная из сценария bash, останавливается, когда сценарий находится в фоновом режиме, но только тогда, когда он получает стандартный ввод из именованного канала?
Когда grep ищет шаблоны в файле с кавычками и/или без кавычек в bash?
Как извлечь столбцы из файла CSV, обработать и создать файл CSV на основе результата извлечения и обработки?
Скрипт Bash, который принимает несколько аргументов пути и проверяет, можно ли там успешно создать файлы
Почему bash не завершает выполнение сценария после ошибки внутри скобок?
Как запустить эмулятор терминала во время работы оболочки?
Как мне отслеживать и уничтожать все процессы, порожденные запуском сценария, не зная имен подпроцессов?
Bash: медленнее использовать zcat по сравнению с cat+zcat или cat+pv+zcat