#sed #awk #sh
#sed #awk #sh
Вопрос:
У меня есть файл переменных окружения, которые я использую в сценариях оболочки, например:
# This is a comment
ONE=1
TWO=2
THREE=THREE
# End
В моих сценариях я добавляю этот файл (предполагаю, что он называется ‘./vars’) в текущую среду и изменяю (некоторые) переменные на основе пользовательского ввода. Например:
#!/bin/sh
# Read variables
source ./vars
# Change a variable
THREE=3
# Write variables back to the file??
awk 'BEGIN{FS="="}{print $1=$$1}' <./vars >./vars
Как вы можете видеть, я экспериментировал с awk для обратной записи переменных, sed тоже. Безуспешно. Последняя строка скрипта завершается ошибкой. Есть ли способ сделать это с помощью awk или sed (предпочтительно с сохранением комментариев, даже комментариев с символом ‘=’)? Или мне следует объединить ‘read’ с сокращением строки в цикле while или каким-либо другим волшебством? Если возможно, я бы хотел избежать perl / python и просто использовать инструменты, доступные в Busybox. Большое спасибо.
Редактировать: возможно, вариант использования мог бы прояснить, в чем моя проблема. Я сохраняю файл конфигурации, состоящий из объявлений переменных среды оболочки:
# File: network.config
NETWORK_TYPE=wired
NETWORK_ADDRESS_RESOLUTION=dhcp
NETWORK_ADDRESS=
NETWORK_ADDRESS_MASK=
У меня также есть скрипт под названием ‘setup-network.sh ‘:
#!/bin/sh
# File: setup-network.sh
# Read configuration
source network.config
# Setup network
NETWORK_DEVICE=none
if [ "$NETWORK_TYPE" == "wired" ]; then
NETWORK_DEVICE=eth0
fi
if [ "$NETWORK_TYPE" == "wireless" ]; then
NETWORK_DEVICE=wlan0
fi
ifconfig -i $NETWORK_DEVICE ...etc
У меня также есть скрипт под названием ‘configure-network.sh ‘:
#!/bin/sh
# File: configure-network.sh
# Read configuration
source network.config
echo "Enter the network connection type:"
echo " 1. Wired network"
echo " 2. Wireless network"
read -p "Type:" -n1 TYPE
if [ "$TYPE" == "1" ]; then
# Update environment variable
NETWORK_TYPE=wired
elif [ "$TYPE" == "2" ]; then
# Update environment variable
NETWORK_TYPE=wireless
fi
# Rewrite configuration file, substituting the updated value
# of NETWORK_TYPE (and any other updated variables already existing
# in the network.config file), so that later invocations of
# 'setup-network.sh' read the updated configuration.
# TODO
Как мне переписать файл конфигурации, обновив только переменные, уже существующие в файле конфигурации, предпочтительно оставив комментарии и пустые строки нетронутыми? Надеюсь, это немного прояснит ситуацию. Еще раз спасибо.
Ответ №1:
Вы не можете использовать awk и выполнять чтение и запись из одного файла (это часть вашей проблемы).
Я предпочитаю переименовать файл перед перезаписью (но вы можете сохранить в tmp, а затем также переименовать).
/bin/mv file file.tmp
awk '.... code ...' file.tmp > file
Если ваш env-файл становится больше, вы увидите, что он усекается при размере буфера вашей операционной системы.
Кроме того, не забывайте, что gawk (std в большинстве установок Linux) имеет встроенную среду array. Вы можете создать из этого все, что хотите
awk 'END {
for (key in ENVIRON) {
print key "=" ENVIRON[key]
}
}' /dev/null
Конечно, вы получаете все в своей среде, так что, возможно, больше, чем вы хотите. Но, вероятно, лучше начать с того, чего вы пытаетесь достичь.
Отредактируйте наиболее конкретно
awk -F"=" '{
if ($1 in ENVIRON) {
printf("%s=%sn", $1, ENVIRON[$1])
}
# else line not printed or add code to meet your situation
}' file > file.tmp
/bin/mv file.tmp file
Правка 2
Я думаю, что ваши значения var =, возможно, потребуется export
отредактировать, чтобы они были видны массиву среды awk.
И
echo PATH=xxx| awk -F= '{print ENVIRON[$1]}'
выводит существующее значение PATH.
Я надеюсь, это поможет.
P.S. поскольку вы, похоже, новый пользователь, если вы получите ответ, который поможет вам, пожалуйста, не забудьте отметить его как принятый и / или поставить ему (или -) в качестве полезного ответа.
Комментарии:
1. Спасибо за подсказку, но опять же, я не думаю, что достаточно ясно выразился. Существует ли sh / sed / awk эквивалент: perl -ne ‘/^([^=] )/; вывести «$1=$ENV{$1}n»;’?
2. Еще раз спасибо. Ваша правка, похоже, больше похожа на то, что мне нужно, однако оператор ENVIRON [$ 1] не расширяется должным образом. Вы можете это перепроверить?
Ответ №2:
Я точно не знаю, что вы пытаетесь сделать, но если вы пытаетесь изменить значение переменной THREE ,
awk -F"=" -vt="$THREE" '$1=="THREE" {$2=t}{print $0>FILENAME}' OFS="=" vars
Комментарии:
1. Извините, что не выразился яснее. Я хочу прочитать переменные из файла в среду (файл представляет собой фрагмент # 1). Затем я хочу обновить одну или две переменные в среде (обновление ТРЕХ — это только пример, это может быть любая из переменных), затем переписать файл с обновленными значениями. Итак: чтение, изменение, запись. Хитрость заключается только в том, чтобы записать обратно переменные, которые были в файле в первую очередь (не всю среду). И сохранение комментариев в исходном файле было бы неплохо.
Ответ №3:
Вы можете сделать это только с помощью bash:
rewrite_config() {
local filename="$1"
local tmp=$(mktemp)
# if you want the header
echo "# File: $filename" >> "$tmp"
while IFS='=' read var value; do
declare -p $var | cut -d ' ' -f 3-
done < "$filename" >> "$tmp"
mv "$tmp" "$filename"
}
Используйте это как
source network.config
# manipulate the variables
rewrite_config network.config
Я использую временный файл, чтобы поддерживать существование файла конфигурации как можно дольше.
Комментарии:
1. Спасибо, Гленн, это хорошее решение. Я не думал об использовании declare. Обратите внимание, что включение заголовка (как в вашем примере) блокирует последующие вызовы rewrite_config , но в остальном это хорошо.
2. Я перебирал различные
eval
решения, пока не прочитал оdeclare
.