He mirado un par de scripts de análisis de bash ini y he vistoesteUno se usó varias veces aquí, así que estoy tratando de ver si funciona para mí. Parece que lee el archivo ini línea por línea varias veces y con cada pasada construye progresivamente una función que finalmente se evalúa. Funciona bien para algunos caracteres especiales pero no para otros. Si un valor en el archivo contiene una comilla simple o un símbolo mayor/menor que, el script devuelve errores de sintaxis. Otros símbolos también crean resultados inesperados. ¿Cómo puedo manejar estos personajes a medida que los encuentro?
Esta es la función que analiza el ini.
#!/usr/bin/env bash
cfg_parser ()
{
ini="$(<$1)" # 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
}
archivo ini
[Section1]
value1=abc`def # unexpected EOF while looking for matching ``'
value2=ghi>jkl # syntax error near unexpected token `>'
value3=mno$pqr # executes ok but outputs "mnoqr"
value4=stu;vwx # executes ok but outputs "stu"
Respuesta1
El hecho de que tupoderhacer algo bash
no significa que túdebería.
sh
(y bash
etc.) los scripts son más adecuados para ser contenedores relativamente simples para iniciar programas o comandos de procesamiento de texto. Para tareas más complicadas, incluido analizar archivos ini y actuar sobre ellos, otros lenguajes son más apropiados. ¿Has considerado escribir tu guión en perl
o python
? Ambos tienen buenos analizadores de archivos .ini: he usado Config::INI
el módulo de Perl varias veces cuando necesitaba analizar un archivo ini.
Pero si insistes en hacerlo en bash, deberías usar una matriz asociativa en lugar de configurar variables individuales.
Comience con algo como esto:
#! /bin/bash
inifile='user1074170.ini'
# declare $config to be an associative array
declare -A config
while IFS='=' read -r key val ; do
config["$key"]="$val"
done < <(sed -E -e '/^\[/d
s/#.*//
s/[[:blank:]]+$|^[[:blank:]]+//g' "$inifile" )
# now print out the config array
set | grep '^config='
El sed
script elimina la [Section1]
línea (en realidad, todas las líneas que comienzan con un corchete abierto [
; querrás manejar esto de manera diferente [1] en un archivo ini con múltiples secciones) y elimina los comentarios, así como los espacios en blanco iniciales y finales. El while
bucle lee cada línea, utilizándola =
como delimitador de campo, y asigna el contenido a las variables $key y $val, que luego se agregan a la matriz $config.
Producción:
config=([value1]="abc\`def" [value3]="mno\$pqr" [value2]="ghi>jkl" [value4]="stu;vwx" )
Puede usar las entradas de la matriz más adelante en su secuencia de comandos de esta manera:
$ echo value1 is "${config[value1]}"
value1 is abc`def
$ [ "${config[value4]}" = 'stu;vwx' ] && echo true
true
[1] awk
o perl
tener formas convenientemente fáciles de leer archivos en modo "párrafo". Un párrafo se define como un bloque de texto separado de otros bloques de texto por una o más líneas en blanco.
Por ejemplo, para trabajar solo con [Section1]
, inserte el awk
siguiente script inmediatamente antes de que el sed
script ingrese al while
bucle anterior:
awk -v RS= -v ORS='\n\n' '/\[Section1\]/' "$inifile" | sed ...
(y eliminar "$inifile"
desde el final de la sed
línea de comando, por supuesto; no desea volver a introducir el archivo después de haberse tomado la molestia de extraer solo [Section1]
de él).
La configuración ORS
no es estrictamente necesaria si solo extrae una sección del archivo ini, pero será útil para mantener la separación de párrafos si extrae dos o más secciones.
Respuesta2
Sé que es una respuesta incompleta, pero MySQL.lns
in augeas parece poder analizar la mayor parte de eso. En augtool
:
augtool> set /augeas/load/testini/incl "/root/test.ini"
augtool> set /augeas/load/testini/lens "MySQL.lns"
augtool> load
augtool> ls /files/root/
.ssh/ test.ini/
augtool> ls /files/root/test.ini
target/ = Section1
augtool> ls /files/root/test.ini/target/
value1/ = abc`def
value2/ = ghi>jkl
value3/ = mno$pqr
value4/ = stu
El único en el que se equivocó es el último y, por cierto, no creo que sea un error. En .ini
los archivos, el punto y coma marca el comienzo de un comentario. También me gustaría preguntar si sus datos realmente se ven así.
Si es así, puede hacer algo sed
antes que establezca ;
algún valor de carácter no utilizado y luego transformarlo nuevamente en el posprocesamiento. Sin embargo, en última instancia, necesitará algunos estándares para que el archivo pueda tener una estructura discernible.
EDITAR:
Lo probé con la lente PHP y obtuve todo siempre que se citaran los valores:
[root@vlzoreman ~]# augtool
augtool> set /augeas/load/testini/lens "PHP.lns"
augtool> set /augeas/load/testini/incl "/root/test.ini"
augtool> load
augtool> ls /files/root/test.ini/Section1/
value1 = abc`def
value2 = ghi>jkl
value3 = mno$pqr
value4 = stu;vwx
De lo contrario, llegó tan lejos como llegó la lente MySQL.
EDITAR #2:
Estoy seguro de que hay una forma más clara de escribir esto, pero este es un ejemplo de uso:
[root@vlp-foreman ~]# bash bash.sh
Values for: Section1:
:: value1 is abc`def
:: value2 is ghi>jkl
:: value3 is mno$pqr
:: value4 is stu;vwx
Values for: Section2:
:: value1 is abc`def
El guión es:
#!/bin/bash
sections=$(augtool -A --transform "PHP.lns incl /root/test.ini" ls /files/root/test.ini | cut -f1 -d/)
for currentSection in $sections; do
echo "Values for: $currentSection:"
fields=$(augtool -A --transform "PHP.lns incl /root/test.ini" ls /files/root/test.ini/$currentSection | awk '{print $1}')
for currentField in $fields; do
currentValue=$(augtool -A --transform "PHP.lns incl /root/test.ini" print /files/root/test.ini/$currentSection/$currentField | cut -f2 -d=)
currentValue=$(echo $currentValue | sed -e 's/^[ \t]*//' -e 's/[ \t]*$//' | sed -e 's/^"//' -e 's/"$//')
echo -e "\t:: $currentField is $currentValue"
done
done
Respuesta3
echa un vistazo a crudini
:https://www.pixelbeat.org/programs/crudini/
en Ubuntu puedes instalarlo para sudo apt install crudini
leer un valor del archivo ini, ejecuta:
$ value1=$(crudini --get "crudini.ini" "Section1" "value1")
crudini admite varios formatos de archivos ini y maneja caracteres especiales:
crudini.ini
[Section1]
value1=abc`def
value2=ghi>jkl
value3=mno$pqr
value4=stu;vwx
valores de lectura
$ for i in {1..4}; do crudini --get "crudini.ini" "Section1" "value$i"; done
abc`def
ghi>jkl
mno$pqr
stu;vwx
$