linux - sustituir - sed shell
¿Cómo uso sed para cambiar mis archivos de configuración, con claves flexibles y valores? (6)
Quiero buscar un archivo de configuración para esta expresión: "central.database". Luego quiero cambiar la configuración asociada con "central.database" a "SQLTEST".
El diseño del archivo de configuración se vería así inicialmente:
central.database = SQLFIRSTTEST
Esto es lo que quiero que se vea después del reemplazo sed:
central.database = SQLTEST
Estoy haciendo esto en un script bash, ¡cualquier sugerencia, recomendación o solución alternativa es bienvenida!
(En realidad, tanto central.database
como SQLTEST
provienen de variables de bash aquí).
Mi código actual (tercer intento):
sshRetValue=$(ssh -p "35903" -i $HOME/sshids/idrsa-1.old ${1} <<EOF
sed -i "s/^/($CENTRAL_DB_NAME/s*=/s*/).*/$//1$CENTRAL_DB_VALUE/" /home/testing.txt;
echo $?
EOF
)
Mensaje de error:
Pseudo-terminal will not be allocated because stdin is not a terminal.
sed: -e expression #1, char 58: unknown option to `s''
-bash: line 3: EOF: command not found
Aquí hay una expresión de ejemplo:
sed -i ''s/^/(central/.database/s*=/s*/).*$//1SQLTEST/'' file.cfg
Si quieres unir cosas con /
en él, puedes usar otro delimitador:
sed -i ''s#^/(cent/ral/.data/base/s*=/s*/).*$#/1SQL/TEST#'' file.cfg
O con expansión variable:
VAL="SQLTEST"
sed -i "s/^/(central/.database/s*=/s*/).*/$//1$VAL/" file.cfg
En tu ejemplo:
sshRetValue=`sed -i "s/^/(/1$CENTRAL_DB_NAME/s*=/s*/).*/$//1$CENTRAL_DB_VALUE/" /home/testing.txt`;
Hay un / 1 antes de $ CENTRAL_DB_NAME que no es válido. Además, sed no imprime su valor de retorno. Esta es la forma preferida de verificar los valores devueltos:
sed -i "s/^/($CENTRAL_DB_NAME/s*=/s*/).*/$//1$CENTRAL_DB_VALUE/" /home/testing.txt;
sed_return_value=$?
Y, finalmente, canalizar a ssh (no probado):
sed_return_value=$(ssh server <<EOF
sed -i "s/^/($CENTRAL_DB_NAME/s*=/s*/).*/$//1$CENTRAL_DB_VALUE/" /home/testing.txt;
echo $?
EOF
)
El -i es para reemplazar datos en el archivo de entrada. De lo contrario, sed escribe en stdout.
Las expresiones regulares son un campo propio. Sería imposible explicarlos en profundidad en una respuesta de , a menos que haya alguna función específica que te elude.
Me gusta usar awk
para esto, ya que es bastante fácil entender lo que está haciendo y se ocupa muy bien del separador ( =
) y también del hecho de que debe hacerse en una línea no comentada:
awk -v var="my_var" -v new_val="NEW VALUE" / # set the vars
''BEGIN{FS=OFS="="} # set separator to =
match($1, "^//s*" var "//s*") { # check if it matches
$2=" " new_val # if so, replace the line
}1'' conf_file # print all lines
Esto usa match()
para verificar si el patrón ocurre en cualquier línea dada. Si lo hace, realiza el reemplazo con el valor dado.
Por ejemplo:
$ cat conf
hello
my_var= SOME VALUE
#my_var = ANOTHER VALUE
bye
Cambiemos el valor en my_var
a NEW VALUE
:
$ awk -v var="my_var" -v new_val="NEW VALUE" ''BEGIN{FS=OFS="="}match($1, "^//s*" var "//s*") {$2=" " new_val}1'' conf
hello
my_var= NEW VALUE
#my_var = ANOTHER VALUE
bye
También es posible establecer los valores en variables de shell y luego usarlos con -v
:
$ var="my_var"
$ new_value="NEW VALUE"
$ awk -v var="$var" -v new_val="$new_value" ''BEGIN{FS=OFS="="}match($1, "^//s*" var "//s*") {$2=" " new_val}1'' conf
Y, por supuesto, puede poner todo esto dentro de una función de shell que luego llama normalmente:
#!/bin/bash
replace () {
file=$1
var=$2
new_value=$3
awk -v var="$var" -v new_val="$new_value" ''BEGIN{FS=OFS="="}match($1, "^//s*" var "//s*") {$2=" " new_val}1'' "$file"
}
# Call the replace() function with the necessary parameters
replace "conf" "my_var" "NEW VALUE"
Tras la ejecución, esto vuelve
hello
my_var= NEW VALUE
#my_var = ANOTHER VALUE
bye
Si bien también puede hacer que el script reciba los parámetros de la siguiente manera: ./script.sh "conf_file" "var_to_replace" "NEW VALUE"
para pasarlos a la función.
Sé que es demasiado tarde para agregar una respuesta a esta pregunta, sin embargo, pensé en compartir mi conocimiento con todos ustedes. Hay un enfoque muy general que he seguido para resolver un tipo similar de problema. He eliminado toda la línea que corresponde a la cadena y he añadido los valores necesarios a esa clave. A tu pregunta aquí está la respuesta
replaceValue=SQLTEST
sed -i "/central.database =/d" /home/testing.txt
echo "central.database = $replaceValue" >> /home/testing.txt
sed elimina la línea de cadena correspondiente del archivo y la siguiente línea inmediata inserta la clave y el valor requeridos en el archivo.
Si desea reemplazar entre 2 archivos de propiedades, puede usar esto:
awk -F= ''NR==FNR{A[$1]=$2;next}$1 in A{$2=A[$1]}1'' OFS=''/='' /tmp/masterfile /opt/props/finalfile.properties > /tmp/tmp.txt && mv -f /tmp/tmp.txt /opt/props/finalfile.properties
Usé este script para mantener las prioridades.
Los argumentos $ 1 tendrán una carpeta en la que existen varios archivos de configuración. $ 2 tendrán propiedades que deben ser reemplazadas en $ 1 ruta y sub paths archivos # 3 tendrán propiedades que necesitan ser reemplazadas por encima de $ 2
También tiene lógica oculta para verificar la existencia de variables de entorno para las claves existentes en $ 2 y $ 3 y dar prioridad a eso.
es decir, si existe una clave en el entorno que sería la más alta prioridad. Al lado de eso sería $ 3 y al lado de eso sería $ 1 archivo.
#!/bin/bash
#Usage is propertyReplacer <CONFIG_FOLDER_PATH> <CONFIG_FILE_2ND_PRIORITY> <CONFIG_FILE_1ST_PRIORITY>
function propertyReplacer() {
filePathToAct="$1"
propertiesFilePath="$2"
propertiesSecureFilePath="$3"
declare -A keyValues
while IFS=''='' read -r key value; do
if [ "$key" == "" ]; then
continue
elif [[ "$key" =~ ^#.*$ ]]; then
continue
else
echo $key " --> " $value
keyValues[$key]=$value
fi
done < "$propertiesFilePath"
if [ ! -f "$propertiesSecureFilePath" ]; then
continue
else
while IFS=''='' read -r key value; do
if [ "$key" == "" ]; then
continue
elif [[ "$key" =~ ^#.*$ ]]; then
continue
else
echo $key " --> " $value
keyValues[$key]=$value
fi
done < "$propertiesSecureFilePath"
fi
for key in ${!keyValues[@]}; do
envProp=${key//[@]/}
if [ "$(eval echo ''$''$envProp)" == "" ]; then
echo "Environment key not exist" $envProp
else
value=$(eval echo ''$''$envProp)
echo "From Environment " $envProp " --> "$value
keyValues[$key]=$value
fi
done
find "$filePathToAct" | while read -r resultFileName; do
if [ ! -f "$resultFileName" ]; then
continue
else
echo "Acting on the file $resultFileName"
for key in ${!keyValues[@]}; do
value=$(echo "${keyValues[${key}]}" | sed ''s/////////g'')
echo "sed -i ''s/$key/$value/g'' $resultFileName "
eval "sed -i ''s/$key/$value/g'' $resultFileName "
done
fi
done
}
sed -i -e ''/central.database =/ s/= .*/= new_value/'' /path/to/file
Explicación:
-
-i
le dice a sed que guarde los resultados en el archivo de entrada. Sin él sed imprimirá los resultados a stdout. -
/central.database =/
coincide con las líneas que contienen la cadena entre barras, es decir, "central.database =". - La parte
s/OLD/NEW/
realiza una sustitución. La secuencia VIEJA es una expresión regular para unir y la parteNEW
es la cadena para sustituirla. - En expresiones regulares,.
.*
Significa "hacer coincidir cualquier cosa". Así que= .*
Coincide con un signo igual, espacio y luego cualquier otra cosa después.