#bash
#bash #синтаксический анализ #переменные #awk
Вопрос:
Наличие следующего содержимого в файле:
VARIABLE1="Value1"
VARIABLE2="Value2"
VARIABLE3="Value3"
Мне нужен скрипт, который выводит следующее:
Content of VARIABLE1 is Value1
Content of VARIABLE2 is Value2
Content of VARIABLE3 is Value3
Есть идеи?
Ответ №1:
Поскольку ваш конфигурационный файл является допустимым сценарием оболочки, вы можете использовать его в своей текущей оболочке:
. config_file
echo "Content of VARIABLE1 is $VARIABLE1"
echo "Content of VARIABLE2 is $VARIABLE2"
echo "Content of VARIABLE3 is $VARIABLE3"
Немного суше, но сложнее
. config_file
for var in VARIABLE1 VARIABLE2 VARIABLE3; do
echo "Content of $var is ${!var}"
done
Комментарии:
1. @samson во-первых, это позволяет вводить любой вредоносный код.
2. Зачем вам беспокоиться о вредоносном коде, вводимом из файла конфигурации? Полагаю, я мог бы представить такие случаи, но мне нужно было иметь возможность делать это из файла, который существует только на моем локальном компьютере, то есть списка комбинаций пользователя и пароля…
3. В этом ответе вам нужно жестко прописать имена переменных. С принятым ответом вы этого не делаете, и это то, что делает его намного лучше.
4. @samson, я бы беспокоился об этом, потому что способ, которым небольшие нарушения безопасности становятся крупными нарушениями безопасности, заключается в том, что злоумышленники находят эксплойты, которые они могут использовать для увеличения своего (часто изначально минимального) доступа. Файл конфигурации с небрежно назначенными разрешениями часто является именно такой возможностью.
5. Я бы также предпочел принятое здесь решение, потому что оно работает в более общих случаях и делает это автоматически независимо от имен и количества переменных
Ответ №2:
awk -F= '{gsub(/"/,"",$2);print "Content of " $1 " is " $2}' <filename>
К вашему сведению, еще одно чистое решение bash
IFS="="
while read -r name value
do
echo "Content of $name is ${value//"/}"
done < filename
Комментарии:
1. Вы также можете использовать
IFS="=" read -r name value
для обработки разделения (-r
это не имеет ничего общего с разделением, но рекомендуется, если у вас нет причин не использовать его).
Ответ №3:
Если вам это нужно…
Характеристики
- Однострочные и встроенные комментарии;
- Обрезка пробелов вокруг
=
(ievar = value
не выйдет из строя); - Строковые значения в кавычках;
- Понимание окончаний строк DOS;
- Соблюдайте безопасность, избегая поиска вашего файла конфигурации.
Код
shopt -s extglob
configfile="dos_or_unix" # set the actual path name of your (DOS or Unix) config file
tr -d 'r' < $configfile > $configfile.unix
while IFS='= ' read -r lhs rhs
do
if [[ ! $lhs =~ ^ *# amp;amp; -n $lhs ]]; then
rhs="${rhs%%#*}" # Del in line right comments
rhs="${rhs%%*( )}" # Del trailing spaces
rhs="${rhs%"*}" # Del opening string quotes
rhs="${rhs#"*}" # Del closing string quotes
declare $lhs="$rhs"
fi
done < $configfile.unix
Комментарии
tr -d 'r' ...
удаляет возврат каретки DOS.
! $lhs =~ ^ *#
пропускает однострочные комментарии и -n $lhs
пропускает пустые строки.
Для удаления конечных пробелов с ${rhs%%*( )}
помощью требуется настройка расширенного глобулирования с shopt -s extglob
помощью . (Помимо использования sed
), вы можете избежать этого с помощью более сложного:
rhs="${rhs%"${rhs##*[^ ]}"}"
Тестовый конфигурационный файл
## This is a comment
var1=value1 # Right side comment
var2 = value2 # Assignment with spaces
## You can use blank lines
var3= Unquoted String # Outer spaces trimmed
var4= "My name is " # Quote to avoid trimming
var5= ""Bob""
Тестовый код
echo "Content of var1 is $var1"
echo "Content of var2 is $var2"
echo "Content of var3 is [$var3]"
echo "Content of var4 var5 is: [$var4$var5]"
Результаты
Content of var1 is value1
Content of var2 is value2
Content of var3 is [Unquoted String]
Content of var4 var5 is: [My name is "Bob"]
Комментарии:
1. Разве rhs =»$ {rhs% » }» для закрывающих кавычек и rhs =»$ {rhs # » }» для открывающих кавычек?
2. и еще одна проблема: когда значение равно «aaaa #AAAAA», скрипт удаляет все в rhs из #
3. Я могу подтвердить, что этот скрипт завершается с ошибкой, если
#
в значении есть a.
Ответ №4:
Я делаю это таким образом
. $PATH_TO_FILE
Комментарии:
1. аналогично тому, что сказал Дэйв Кеннеди, это позволяет вводить любой вредоносный код
2. Только если кто-то изменит исходный файл в «$ PATH_TO_FILE» на другой. Если кто-то может это сделать, значит, системный администратор неаккуратен.
Ответ №5:
awk '{print "Content of "$1" is "$3}' FS='[="]'
Результат
Содержимое ПЕРЕМЕННОЙ 1 равно значению1 Содержимое ПЕРЕМЕННОЙ 2 равно значению2 Содержимое ПЕРЕМЕННОЙ 3 равно значению3
Ответ №6:
#
#------------------------------------------------------------------------------
# parse the ini like $0.$host_name.cnf and set the variables
# cleans the unneeded during after run-time stuff. Note the MainSection
# courtesy of : http://mark.aufflick.com/blog/2007/11/08/parsing-ini-files-with-sed
#------------------------------------------------------------------------------
doParseConfFile(){
# set a default cnfiguration file
cnf_file="$run_unit_bash_dir/$run_unit.cnf"
# however if there is a host dependant cnf file override it
test -f "$run_unit_bash_dir/$run_unit.$host_name.cnf"
amp;amp; cnf_file="$run_unit_bash_dir/$run_unit.$host_name.cnf"
# yet finally override if passed as argument to this function
# if the the ini file is not passed define the default host independant ini file
test -z "$1" || cnf_file=$1;shift 1;
test -z "$2" || ini_section=$2;shift 1;
doLog "DEBUG read configuration file : $cnf_file"
doLog "INFO read [$ini_section] section from config file"
# debug echo "@doParseConfFile cnf_file:: $cnf_file"
# coud be later on parametrized ...
test -z "$ini_section" amp;amp; ini_section='MAIN_SETTINGS'
doLog "DEBUG reading: the following configuration file"
doLog "DEBUG ""$cnf_file"
( set -o posix ; set ) | sort >"$tmp_dir/vars.before"
eval `sed -e 's/[[:space:]]*=[[:space:]]*/=/g'
-e 's/#.*$//'
-e 's/[[:space:]]*$//'
-e 's/^[[:space:]]*//'
-e "s/^(.*)=([^"']*)$/1="2"/"
< $cnf_file
| sed -n -e "/^[$ini_section]/,/^s*[/{/^[^#].*=.*/p;}"`
( set -o posix ; set ) | sort >"$tmp_dir/vars.after"
doLog "INFO added the following vars from section: [$ini_section]"
cmd="$(comm -3 $tmp_dir/vars.before $tmp_dir/vars.after | perl -ne 's#s ##g;print "n $_ "' )"
echo -e "$cmd"
echo -e "$cmd" >> $log_file
echo -e "nn"
sleep 1; printf "33[2J";printf "33[0;0H" # and clear the screen
}
#eof func doParseConfFile
Ответ №7:
задан конфигурационный файл следующим образом :-
[a]
b=C
d=E;rm t1
[b]
g=h
следующая однострочная строка проанализирует и сохранит значения :-
CFG=path-to-file; for ini in `awk '/^[/' $CFG`;do unset ARHG;declare -A ARHG;while read A B;do ARHG[$A]=$B;echo "in section $ini, $A is equal to" ${ARHG["$A"]};done < <(awk -F'=' '/[/ {x=0} x==1 amp;amp; $0~/=/ amp;amp; NF==2 {print $1, $2} $0==INI {x=1}' INI="$ini" $CFG);declare -p ARHG;echo;done;printf "end loopnn";declare -p ARHG
Теперь давайте разберем это
CFG=path-to-file;
for ini in `awk '/^[/' $CFG` # finds the SECTIONS (aka "ini")
do
unset ARHG # resets ARHG
declare -A ARHG # declares an associative array
while read A B
do
ARHG[$A]=$B
echo "in section $ini, $A is equal to" ${ARHG["$A"]}
done < <(awk -F'=' '/[/ {x=0} x==1 amp;amp; $0~/=/ amp;amp; NF==2 {print $1, $2} $0==INI {x=1}' INI="$ini" $CFG)
# the awk splits the file into sections,
# and returns pairs of values separated by "="
declare -p ARHG # displays the current contents of ARHG
echo
done
printf "end loopnn"
declare -p ARHG
Это позволяет нам сохранять значения, не используя eval или backtick.
Чтобы быть «действительно чистым», мы могли бы удалить [:space:] в начале и конце строки, игнорировать строки «^ #» и убрать пробелы вокруг знака «равно».
Комментарии:
1. конечно, для использования «declare -A» требуется последняя версия bash. Например, «GNU bash, версия 3.2.57 (1)-release (x86_64-apple-darwin14)» НЕ включает параметр «-A»…