Comment saisir une valeur INI dans un script shell?
j'ai des paramètres.fichier ini, tel que:
[parameters.ini]
database_user = user
database_version = 20110611142248
je veux lire et utiliser la version de base de données spécifié dans les paramètres.fichier ini à partir d'un script shell bash pour que je puisse le traiter.
#!/bin/sh
# Need to get database version from parameters.ini file to use in script
php app/console doctrine:migrations:migrate $DATABASE_VERSION
Comment faire?
23 réponses
Que Diriez-vous de grapper pour cette ligne puis en utilisant awk
version=$(awk -F "=" '/database_version/ {print }' parameters.ini)
vous pouvez utiliser bash native parser pour interpréter les valeurs ini, par:
$ source <(grep = file.ini)
exemple de fichier:
[section-a]
var1=value1
var2=value2
IPS=( "1.2.3.4" "1.2.3.5" )
pour accéder aux variables, il suffit de les imprimer: echo $var1
. Vous pouvez également utiliser des tableaux comme indiqué ci-dessus ( echo ${IPS[@]}
).
si vous voulez seulement une valeur unique grep juste pour elle:
source <(grep var1 file.ini)
C'est simple vous n'avez pas besoin d'aucune bibliothèque externe pour analyser les données, mais il vient avec quelques inconvénients. Par exemple:
-
si vous avez des espaces entre
=
(nom variable et valeur), alors vous devez couper les espaces en premier, par exemple$ source <(grep = file.ini | sed 's/ *= */=/g')
- "1519210920 Pour" soutenir
;
les commentaires, les remplacer par des#
:$ sed "s/;/#/g" foo.ini | source /dev/stdin
-
les sections ne sont pas supportées (par ex. si vous avez
[section-name]
, alors vous avez pour le filtrer comme indiqué ci-dessus, par exemplegrep =
), la même chose pour les autres erreurs inattendues.si vous avez besoin de lire la valeur spécifique sous section spécifique, utilisez
grep -A
,sed
,awk
ouex
).E. G.
source <(grep = <(grep -A5 '\[section-b\]' file.ini))
Note: où
-A5
est le nombre de lignes à lire dans la section. Remplacersource
parcat
pour déboguer. -
si vous avez des erreurs d'analyse, ignorez-les en ajoutant:
2>/dev/null
voir aussi: comment analyser et convertir un fichier ini en variables de tableaux de bash? at serverfault SE
Bash ne fournissent pas un analyseur pour ces fichiers, évidemment vous pouvez utiliser un code awk ou un couple d'appels sed, mais si vous êtes bash-priest et ne voulez pas utiliser plus, alors vous pouvez essayer le code obscur suivant:
#!/usr/bin/env bash
cfg_parser ()
{
ini="$(<)" # read the file
ini="${ini//[/\[}" # escape [
ini="${ini//]/\]}" # escape ]
IFS=$'\n' && ini=( ${ini} ) # convert to line-array
ini=( ${ini[*]//;*/} ) # remove comments with ;
ini=( ${ini[*]/\ =/=} ) # remove tabs before =
ini=( ${ini[*]/=\ /=} ) # remove tabs be =
ini=( ${ini[*]/\ =\ /=} ) # remove anything with a space around =
ini=( ${ini[*]/#\[/\}$'\n'cfg.section.} ) # set section prefix
ini=( ${ini[*]/%\]/ \(} ) # convert text2function (1)
ini=( ${ini[*]/=/=\( } ) # convert item to array
ini=( ${ini[*]/%/ \)} ) # close array parenthesis
ini=( ${ini[*]/%\ \)/ \} ) # the multiline trick
ini=( ${ini[*]/%\( \)/\(\) \{} ) # convert text2function (2)
ini=( ${ini[*]/%\} \)/\}} ) # remove extra parenthesis
ini[0]="" # remove first element
ini[${#ini[*]} + 1]='}' # add the last brace
eval "$(echo "${ini[*]}")" # eval the result
}
cfg_writer ()
{
IFS=' '$'\n'
fun="$(declare -F)"
fun="${fun//declare -f/}"
for f in $fun; do
[ "${f#cfg.section}" == "${f}" ] && continue
item="$(declare -f ${f})"
item="${item##*\{}"
item="${item%\}}"
item="${item//=*;/}"
vars="${item//=*/}"
eval $f
echo "[${f#cfg.section.}]"
for var in $vars; do
echo $var=\"${!var}\"
done
done
}
Utilisation:
# parse the config file called 'myfile.ini', with the following
# contents::
# [sec2]
# var2='something'
cfg.parser 'myfile.ini'
# enable section called 'sec2' (in the file [sec2]) for reading
cfg.section.sec2
# read the content of the variable called 'var2' (in the file
# var2=XXX). If your var2 is an array, then you can use
# ${var[index]}
echo "$var2"
Bash ini-parser peut être trouvé à la vieille école DevOps blog site .
incluez juste votre .fichier ini dans le corps bash:
Fichier exemple.ini :
DBNAME=test
DBUSER=scott
DBPASSWORD=tiger
File example.sh
#!/bin/bash
#Including .ini file
. example.ini
#Test
echo "${DBNAME} ${DBUSER} ${DBPASSWORD}"
Sed one-liner, qui prend en compte les sections. Exemple de fichier:
[section1]
param1=123
param2=345
param3=678
[section2]
param1=abc
param2=def
param3=ghi
[section3]
param1=000
param2=111
param3=222
dit que vous voulez param2 de la section 2. Exécutez ce qui suit:
sed -nr "/^\[section2\]/ { :l /^param2[ ]*=/ { s/.*=[ ]*//; p; q;}; n; b l;}" ./file.ini
vous donnera
def
l'une des solutions possibles
dbver=$(sed -n 's/.*database_version *= *\([^ ]*.*\)//p' < parameters.ini)
echo $dbver
toutes les solutions que j'ai vu jusqu'à présent ont également frappé sur les lignes commentées. Celui-ci ne l'a pas fait, si le code de commentaire est ;
:
awk -F '=' '{if (! ("151900920" ~ /^;/) && "151900920" ~ /database_version/) print }' file.ini
afficher la valeur de my_key dans un style ini my_file :
sed -n -e 's/^\s*my_key\s*=\s*//p' my_file
-
-n
-- n'Imprimez rien par défaut -
-e
-- exécuter l'expression -
s/PATTERN//p
-- afficher tout ce qui suit Ce modèle Dans le dessin: -
^
-- le motif commence au début de la ligne -
\s
-- caractère d'espace -
*
-- zéro ou plusieurs (les espaces)
exemple:
$ cat my_file
# Example INI file
something = foo
my_key = bar
not_my_key = baz
my_key_2 = bing
$ sed -n -e 's/^\s*my_key\s*=\s*//p' my_file
bar
:
trouver un modèle où la ligne commence avec zéro ou de nombreux caractères d'espace, suivi de la chaîne my_key , suivi de zéro ou de nombreux caractères blancs, un signe égal, puis zéro ou plusieurs caractères espace nouveau. Afficher le reste du contenu sur cette ligne en suivant ce modèle.
pour les personnes (comme moi) qui cherchent à lire des fichiers INI à partir de scripts shell (lire shell, pas bash) - j'ai créé la petite bibliothèque helper qui essaie de faire exactement cela:
https://github.com/wallyhall/shini (licence MIT, faire avec elle comme vous s'il vous plaît. J'ai fait le lien ci-dessus en l'incluant en ligne car le code est assez long.)
c'est un peu plus "compliqué" que les lignes simples sed
suggérées ci - dessus-mais fonctionne sur une base similaire.
lit dans un fichier ligne par ligne les marqueurs de section ( [section]
) et les déclarations de clé/valeur ( key=value
).
finalement vous obtenez un rappel à votre propre fonction - section, clé et valeur.
vous pouvez utiliser sed
pour analyser le fichier de configuration ini, surtout quand vous avez des noms de sections comme:
# last modified 1 April 2001 by John Doe
[owner]
name=John Doe
organization=Acme Widgets Inc.
[database]
# use IP address in case network name resolution is not working
server=192.0.2.62
port=143
file=payroll.dat
donc vous pouvez utiliser le script suivant sed
pour analyser les données ci-dessus:
# Configuration bindings found outside any section are given to
# to the default section.
1 {
x
s/^/default/
x
}
# Lines starting with a #-character are comments.
/#/n
# Sections are unpacked and stored in the hold space.
/\[/ {
s/\[\(.*\)\]//
x
b
}
# Bindings are unpacked and decorated with the section
# they belong to, before being printed.
/=/ {
s/^[[:space:]]*//
s/[[:space:]]*=[[:space:]]*/|/
G
s/\(.*\)\n\(.*\)/|/
p
}
cela convertira les données ini dans ce format plat:
owner|name|John Doe
owner|organization|Acme Widgets Inc.
database|server|192.0.2.62
database|port|143
database|file|payroll.dat
ainsi il sera plus facile de parser en utilisant sed
, awk
ou read
en ayant des noms de section dans chaque ligne.
Credits & source: fichiers de Configuration pour les scripts shell , Michael Grünewald
Certaines réponses ne respectent pas les commentaires. Certains ne respectent pas les articles. Certains ne reconnaissent qu'une syntaxe ( " :", ou seulement "="). Certaines réponses Python échouent sur ma machine à cause d'une captialisation différente ou d'un défaut d'importer le module sys. Elles sont toutes un peu trop courtes pour moi.
donc j'ai écrit le mien, et si vous avez un Python moderne, vous pouvez probablement l'appeler de votre coquille de Bash. Il a l'avantage d'adhérer à certains des codes Python communs les conventions, et même fournit des messages d'erreur sensée et de l'aide. Pour l'utiliser, le nom de quelque chose comme myconfig.py (ne l'appelez PAS configparser.py ou il peut tenter d'importer lui-même), de le rendre exécutable, et de l'appeler comme
value=$(myconfig.py something.ini sectionname value)
Voici mon code pour Python 3.5 sous Linux:
#!/usr/bin/env python3
# Last Modified: Thu Aug 3 13:58:50 PDT 2017
"""A program that Bash can call to parse an .ini file"""
import sys
import configparser
import argparse
if __name__ == '__main__':
parser = argparse.ArgumentParser(description="A program that Bash can call to parse an .ini file")
parser.add_argument("inifile", help="name of the .ini file")
parser.add_argument("section", help="name of the section in the .ini file")
parser.add_argument("itemname", help="name of the desired value")
args = parser.parse_args()
config = configparser.ConfigParser()
config.read(args.inifile)
print(config.get(args.section, args.itemname))
voici ma version, qui analyse les sections et popule un tableau associatif global g_iniProperties avec elle. Notez que cela ne fonctionne qu'avec bash v4.2 et plus.
function parseIniFile() { #accepts the name of the file to parse as argument ()
#declare syntax below (-gA) only works with bash 4.2 and higher
unset g_iniProperties
declare -gA g_iniProperties
currentSection=""
while read -r line
do
if [[ $line = [* ]] ; then
if [[ $line = [* ]] ; then
currentSection=$(echo $line | sed -e 's/\r//g' | tr -d "[]")
fi
else
if [[ $line = *=* ]] ; then
cleanLine=$(echo $line | sed -e 's/\r//g')
key=$currentSection.$(echo $cleanLine | awk -F: '{ st = index("151900920","=");print substr("151900920",0,st-1)}')
value=$(echo $cleanLine | awk -F: '{ st = index("151900920","=");print substr("151900920",st+1)}')
g_iniProperties[$key]=$value
fi
fi;
done <
}
Et voici un exemple de code utilisant la fonction ci-dessus:
parseIniFile "/path/to/myFile.ini"
for key in "${!g_iniProperties[@]}"; do
echo "Found key/value $key = ${g_iniProperties[$key]}"
done
ce script obtiendra les paramètres suivants:
signifie que si votre ini a:
pars_ini.ksh < chemin vers le fichier ini > < nom du secteur dans le fichier Ini > < nom dans le nom=valeur à retourner >
par exemple. comment l'appeler :
[ environnement]
a=x
[ DataBase_Sector]
DSN = quelque chose
puis appel:
pars_ini.ksh /utilisateurs/bubu_user/paramètres.base de Données_secteur DSN
cela va récupérer le "quelque chose" suivant
le script "pars_ini.ksh":
\#!/bin/ksh
\#INI_FILE=path/to/file.ini
\#INI_SECTION=TheSection
\# BEGIN parse-ini-file.sh
\# SET UP THE MINIMUM VARS FIRST
alias sed=/usr/local/bin/sed
INI_FILE=
INI_SECTION=
INI_NAME=
INI_VALUE=""
eval `sed -e 's/[[:space:]]*\=[[:space:]]*/=/g' \
-e 's/;.*$//' \
-e 's/[[:space:]]*$//' \
-e 's/^[[:space:]]*//' \
-e "s/^\(.*\)=\([^\"']*\)$/=\"\"/" \
< $INI_FILE \
| sed -n -e "/^\[$INI_SECTION\]/,/^\s*\[/{/^[^;].*\=.*/p;}"`
TEMP_VALUE=`echo "$"$INI_NAME`
echo `eval echo $TEMP_VALUE`
Ma version de la one-liner
#!/bin/bash
#Reader for MS Windows 3.1 Ini-files
#Usage: inireader.sh
# e.g.: inireader.sh win.ini ERRORS DISABLE
# would return value "no" from the section of win.ini
#[ERRORS]
#DISABLE=no
INIFILE=
SECTION=
ITEM=
cat $INIFILE | sed -n /^\[$SECTION\]/,/^\[.*\]/p | grep "^[:space:]*$ITEM[:space:]*=" | sed s/.*=[:space:]*//
vient de finir d'écrire mon propre parser. J'ai essayé d'utiliser divers analyseurs trouvés ici, aucun ne semble fonctionner à la fois avec ksh93 (AIX) et bash (Linux).
c'est un vieux style de programmation - parsing ligne par ligne. Assez rapide car peu de commandes externes. Un peu plus lent en raison de toute l'évaluation requise pour le nom dynamique du tableau.
L'ini de soutien 3 spécial syntaxs:
- includefile=fichier ini --> Charger un fichier ini supplémentaire. Utile pour diviser le ini en plusieurs fichiers, ou réutiliser un morceau de configuration
- includedir=répertoire --> Identique à includefile, mais inclure un répertoire complet
- includesection=section --> Copier une section existante dans la section courante.
j'ai utilisé toute cette syntaxe pour avoir un fichier ini assez complexe et réutilisable. Utile pour installer des produits lors de l'installation d'un nouveau système D'exploitation - nous le faisons souvent.
Les valeurspeuvent être consultées avec ${ini[$section.$article.}] Le tableau doit être défini avant de l'appeler.
amusez-vous bien. J'espère que c'est utile pour quelqu'un d'autre!
function Show_Debug {
[[ $DEBUG = YES ]] && echo "DEBUG $@"
}
function Fatal {
echo "$@. Script aborted"
exit 2
}
#-------------------------------------------------------------------------------
# This function load an ini file in the array "ini"
# The "ini" array must be defined in the calling program (typeset -A ini)
#
# It could be any array name, the default array name is "ini".
#
# There is heavy usage of "eval" since ksh and bash do not support
# reference variable. The name of the ini is passed as variable, and must
# be "eval" at run-time to work. Very specific syntax was used and must be
# understood before making any modifications.
#
# It complexify greatly the program, but add flexibility.
#-------------------------------------------------------------------------------
function Load_Ini {
Show_Debug ""151900920"($@)"
typeset ini_file=""
# Name of the array to fill. By default, it's "ini"
typeset ini_array_name="${2:-ini}"
typeset section variable value line my_section file subsection value_array include_directory all_index index sections pre_parse
typeset LF="
"
if [[ ! -s $ini_file ]]; then
Fatal "The ini file is empty or absent in "151900920" [$ini_file]"
fi
include_directory=$(dirname $ini_file)
include_directory=${include_directory:-$(pwd)}
Show_Debug "include_directory=$include_directory"
section=""
# Since this code support both bash and ksh93, you cannot use
# the syntax "echo xyz|while read line". bash doesn't work like
# that.
# It forces the use of "<<<", introduced in bash and ksh93.
Show_Debug "Reading file $ini_file and putting the results in array $ini_array_name"
pre_parse="$(sed 's/^ *//g;s/#.*//g;s/ *$//g' <$ini_file | egrep -v '^$')"
while read line; do
if [[ ${line:0:1} = "[" ]]; then # Is the line starting with "["?
# Replace [section_name] to section_name by removing the first and last character
section="${line:1}"
section="${section%\]}"
eval "sections=${$ini_array_name[sections_list]}"
sections="$sections${sections:+ }$section"
eval "$ini_array_name[sections_list]=\"$sections\""
Show_Debug "$ini_array_name[sections_list]=\"$sections\""
eval "$ini_array_name[$section.exist]=YES"
Show_Debug "$ini_array_name[$section.exist]='YES'"
else
variable=${line%%=*} # content before the =
value=${line#*=} # content after the =
if [[ $variable = includefile ]]; then
# Include a single file
Load_Ini "$include_directory/$value" "$ini_array_name"
continue
elif [[ $variable = includedir ]]; then
# Include a directory
# If the value doesn't start with a /, add the calculated include_directory
if [[ $value != /* ]]; then
value="$include_directory/$value"
fi
# go thru each file
for file in $(ls $value/*.ini 2>/dev/null); do
if [[ $file != *.ini ]]; then continue; fi
# Load a single file
Load_Ini "$file" "$ini_array_name"
done
continue
elif [[ $variable = includesection ]]; then
# Copy an existing section into the current section
eval "all_index=\"${!$ini_array_name[@]}\""
# It's not necessarily fast. Need to go thru all the array
for index in $all_index; do
# Only if it is the requested section
if [[ $index = $value.* ]]; then
# Evaluate the subsection [section.subsection] --> subsection
subsection=${index#*.}
# Get the current value (source section)
eval "value_array=\"${$ini_array_name[$index]}\""
# Assign the value to the current section
# The $value_array must be resolved on the second pass of the eval, so make sure the
# first pass doesn't resolve it ($value_array instead of $value_array).
# It must be evaluated on the second pass in case there is special character like ,
# or ' or " in it (code).
eval "$ini_array_name[$section.$subsection]=\"$value_array\""
Show_Debug "$ini_array_name[$section.$subsection]=\"$value_array\""
fi
done
fi
# Add the value to the array
eval "current_value=\"${$ini_array_name[$section.$variable]}\""
# If there's already something for this field, add it with the current
# content separated by a LF (line_feed)
new_value="$current_value${current_value:+$LF}$value"
# Assign the content
# The $new_value must be resolved on the second pass of the eval, so make sure the
# first pass doesn't resolve it ($new_value instead of $new_value).
# It must be evaluated on the second pass in case there is special character like ,
# or ' or " in it (code).
eval "$ini_array_name[$section.$variable]=\"$new_value\""
Show_Debug "$ini_array_name[$section.$variable]=\"$new_value\""
fi
done <<< "$pre_parse"
Show_Debug "exit "151900920"($@)\n"
}
cette implémentation utilise awk
et présente les avantages suivants:
- ne retourne que le premier correspondant à l'entrée
- ignore les lignes qui commencent par un
;
- Trims menant et traînant espace blanc, mais pas l'espace blanc interne
version formatée :
awk -F '=' '/^\s*database_version\s*=/ {
sub(/^ +/, "", );
sub(/ +$/, "", );
print ;
exit;
}' parameters.ini
One-liner :
awk -F '=' '/^\s*database_version\s*=/ { sub(/^ +/, "", ); sub(/ +$/, "", ); print ; exit; }' parameters.ini
quand j'utilise un mot de passe dans base64, je mets le séparateur ":" parce que la chaîne base64 peut avoir "=". Par exemple (j'utilise ksh
):
> echo "Abc123" | base64
QWJjMTIzCg==
Dans parameters.ini
mettre la ligne pass:QWJjMTIzCg==
, et enfin:
> PASS=`awk -F":" '/pass/ {print }' parameters.ini | base64 --decode`
> echo "$PASS"
Abc123
si la ligne a des espaces comme "pass : QWJjMTIzCg== "
ajouter | tr -d ' '
pour les couper:
> PASS=`awk -F":" '/pass/ {print }' parameters.ini | tr -d ' ' | base64 --decode`
> echo "[$PASS]"
[Abc123]
similaire aux autres réponses Python, vous pouvez le faire en utilisant le drapeau -c
pour exécuter une séquence D'instructions Python données sur la ligne de commande:
$ python3 -c "import configparser; c = configparser.ConfigParser(); c.read('parameters.ini'); print(c['parameters.ini']['database_version'])"
20110611142248
ceci a l'avantage de n'exiger que la bibliothèque standard de Python et l'avantage de ne pas écrire un fichier de script séparé.
simplicité complexe
fichier ini
test.ini
[section1]
name1=value1
name2=value2
[section2]
name1=value_1
name2 = value_2
script bash avec lecture et exécution
/ bin /parseini
#!/bin/bash
set +a
while read p; do
reSec='^\[(.*)\]$'
#reNV='[ ]*([^ ]*)+[ ]*=(.*)' #Remove only spaces around name
reNV='[ ]*([^ ]*)+[ ]*=[ ]*(.*)' #Remove spaces around name and spaces before value
if [[ $p =~ $reSec ]]; then
section=${BASH_REMATCH[1]}
elif [[ $p =~ $reNV ]]; then
sNm=${section}_${BASH_REMATCH[1]}
sVa=${BASH_REMATCH[2]}
set -a
eval "$(echo "$sNm"=\""$sVa"\")"
set +a
fi
done <
puis dans un autre script Je source les résultats de la commande et je peux utiliser n'importe quelles variables dans
test.sh
#!/bin/bash
source parseini test.ini
echo $section2_name2
enfin de la ligne de commande la sortie est donc
# ./test.sh
value_2
j'ai écrit un script python rapide et facile à inclure dans mon script bash.
par exemple, votre fichier ini s'appelle food.ini
et dans le fichier, vous pouvez avoir quelques articles et quelques lignes:
[FRUIT]
Oranges = 14
Apples = 6
Copiez ce petit script Python de 6 lignes et enregistrez-le comme configparser.py
#!/usr/bin/python
import configparser
import sys
config = configpParser.ConfigParser()
config.read(sys.argv[1])
print config.get(sys.argv[2],sys.argv[3])
maintenant, dans votre script bash vous pouvez faire ceci par exemple.
OrangeQty=$(python configparser.py food.ini FRUIT Oranges)
ou
ApplesQty=$(python configparser.py food.ini FRUIT Apples)
echo $ApplesQty
Ce preposes:
- vous avez installé Python
- vous avez configparser library installé (cela devrait venir avec une installation de Python std)
j'Espère que ça aide :)
utilise le système perl et nettoie les expressions régulières:
cat parameters.ini | perl -0777ne 'print "" if /\[\s*parameters\.ini\s*\][\s\S]*?\sdatabase_version\s*=\s*(.*)/'
la réponse de "Karen Gabrielyan" parmi d'autres réponses était la meilleure, mais dans certains environnements nous n'avons pas awk, comme busybox typique, j'ai changé la réponse par code ci-dessous.
trim()
{
local trimmed=""
# Strip leading space.
trimmed="${trimmed## }"
# Strip trailing space.
trimmed="${trimmed%% }"
echo "$trimmed"
}
function parseIniFile() { #accepts the name of the file to parse as argument ()
#declare syntax below (-gA) only works with bash 4.2 and higher
unset g_iniProperties
declare -gA g_iniProperties
currentSection=""
while read -r line
do
if [[ $line = [* ]] ; then
if [[ $line = [* ]] ; then
currentSection=$(echo $line | sed -e 's/\r//g' | tr -d "[]")
fi
else
if [[ $line = *=* ]] ; then
cleanLine=$(echo $line | sed -e 's/\r//g')
key=$(trim $currentSection.$(echo $cleanLine | cut -d'=' -f1'))
value=$(trim $(echo $cleanLine | cut -d'=' -f2))
g_iniProperties[$key]=$value
fi
fi;
done <
}