web-dev-qa-db-fra.com

Remplacer les variables d'environnement dans un fichier par leurs valeurs réelles?

Existe-t-il un moyen simple de remplacer/évaluer les variables d'environnement dans un fichier? Comme disons que j'ai un fichier config.xml cela contient:

<property>
    <name>instanceId</name>
    <value>$INSTANCE_ID</value>
</property>
<property>
    <name>rootPath</name>
    <value>/services/$SERVICE_NAME</value>
</property>

...etc. Je veux remplacer $INSTANCE_ID dans le fichier avec la valeur de INSTANCE_ID variable d'environnement, $SERVICE_NAME avec la valeur de SERVICE_NAME env var. Je ne saurai pas a priori quelles variables d'environnement sont nécessaires (ou plutôt, je ne veux pas avoir à mettre à jour le script si quelqu'un ajoute une nouvelle variable d'environnement au fichier de configuration). Merci!

50
Robert Fraser

Vous pouvez utiliser envsubst (partie de gnu gettext):

envsubst < infile

remplacera les variables d'environnement de votre fichier par leur valeur correspondante. Les noms de variables doivent être constitués uniquement de caractères alphanumériques ou de soulignement ASCII caractères, ne commencez pas par un chiffre et ne soyez pas vide; sinon, une telle référence de variable est ignoré.


Pour remplacer uniquement certaines variables d'environnement, voir cette question.

81
don_crissti

Ce n'est pas très sympa mais ça marche

( echo "cat <<EOF" ; cat config.xml ; echo EOF ) | sh

Si c'était dans un script Shell, cela ressemblerait à:

#! /bin/sh
cat <<EOF
<property>
    <name>instanceId</name>
    <value>$INSTANCE_ID</value>
</property>
EOF

Edit, deuxième proposition:

eval "echo \"$(cat config.xml)\""

Modifier, pas strictement lié à la question, mais en cas de variables lues à partir du fichier:

(. .env && eval "echo \"$(cat config.xml)\"")
23
hschou

S'il vous arrive d'avoir Perl (mais pas gettext et envsubst), vous pouvez faire le remplacement simple avec un court script:

$ export INSTANCE_ID=foo; export SERVICE_NAME=bar;
$ Perl -pe 's/\$([_A-Z]+)/$ENV{$1}/g'  < config.xml
<property>
    <name>instanceId</name>
    <value>foo</value>
</property>
<property>
    <name>rootPath</name>
    <value>/services/bar</value>
</property>

J'ai supposé que les noms de variables n'auront que des lettres majuscules et des traits de soulignement, mais le premier modèle devrait être facile à modifier selon les besoins. $ENV{...} fait référence à l'environnement que Perl voit.

Si vous souhaitez prendre en charge le ${...} syntaxe ou lancer une erreur sur les variables non définies, vous aurez besoin de plus de travail. Un équivalent proche de gettextenvsubst serait:

Perl -pe 's/\$(\{)?([a-zA-Z_]\w*)(?(1)\})/$ENV{$2}/g'

Bien que je pense que l'alimentation de variables comme celle-ci via l'environnement de processus semble un peu aléatoire en général: vous ne pouvez pas utiliser de variables arbitraires dans les fichiers (car elles peuvent avoir des significations spéciales), et certaines des valeurs peuvent éventuellement avoir au moins des données sensibles en eux.

9
ilkkachu

Puis-je suggérer mon propre script pour cela?

https://github.com/rydnr/set-square/blob/master/.templates/common-files/process-file.sh

#!/bin/bash /usr/local/bin/dry-wit
# Copyright 2016-today Automated Computing Machinery S.L.
# Distributed under the terms of the GNU General Public License v3

function usage() {
cat <<EOF
$SCRIPT_NAME -o|--output output input
$SCRIPT_NAME [-h|--help]
(c) 2016-today Automated Computing Machinery S.L.
    Distributed under the terms of the GNU General Public License v3

Processes a file, replacing any placeholders with the contents of the
environment variables, and stores the result in the specified output file.

Where:
    * input: the input file.
    * output: the output file.
Common flags:
    * -h | --help: Display this message.
    * -v: Increase the verbosity.
    * -vv: Increase the verbosity further.
    * -q | --quiet: Be silent.
EOF
}

# Requirements
function checkRequirements() {
  checkReq envsubst ENVSUBST_NOT_INSTALLED;
}

# Error messages
function defineErrors() {
  export INVALID_OPTION="Unrecognized option";
  export ENVSUBST_NOT_INSTALLED="envsubst is not installed";
  export NO_INPUT_FILE_SPECIFIED="The input file is mandatory";
  export NO_OUTPUT_FILE_SPECIFIED="The output file is mandatory";

  ERROR_MESSAGES=(\
    INVALID_OPTION \
    ENVSUBST_NOT_INSTALLED \
    NO_INPUT_FILE_SPECIFIED \
    NO_OUTPUT_FILE_SPECIFIED \
  );

  export ERROR_MESSAGES;
}

## Parses the input
## dry-wit hook
function parseInput() {

  local _flags=$(extractFlags $@);
  local _flagCount;
  local _currentCount;

  # Flags
  for _flag in ${_flags}; do
    _flagCount=$((_flagCount+1));
    case ${_flag} in
      -h | --help | -v | -vv | -q)
         shift;
         ;;
      -o | --output)
         shift;
         OUTPUT_FILE="${1}";
         shift;
         ;;
    esac
  done

  # Parameters
  if [[ -z ${INPUT_FILE} ]]; then
    INPUT_FILE="$1";
    shift;
  fi
}

## Checking input
## dry-wit hook
function checkInput() {

  local _flags=$(extractFlags $@);
  local _flagCount;
  local _currentCount;
  logDebug -n "Checking input";

  # Flags
  for _flag in ${_flags}; do
    _flagCount=$((_flagCount+1));
    case ${_flag} in
      -h | --help | -v | -vv | -q | --quiet)
         ;;
      -o | --output)
         ;;
      *) logDebugResult FAILURE "fail";
         exitWithErrorCode INVALID_OPTION ${_flag};
         ;;
    esac
  done

  if [[ -z ${INPUT_FILE} ]]; then
    logDebugResult FAILURE "fail";
    exitWithErrorCode NO_INPUT_FILE_SPECIFIED;
  fi

  if [[ -z ${OUTPUT_FILE} ]]; then
      logDebugResult FAILURE "fail";
      exitWithErrorCode NO_OUTPUT_FILE_SPECIFIED;
  fi
}

## Replaces any placeholders in given file.
## -> 1: The file to process.
## -> 2: The output file.
## <- 0 if the file is processed, 1 otherwise.
## <- RESULT: the path of the processed file.
function replace_placeholders() {
  local _file="${1}";
  local _output="${2}";
  local _rescode;
  local _env="$(IFS=" \t" env | awk -F'=' '{printf("%s=\"%s\" ", $1, $2);}')";
  local _envsubstDecl=$(echo -n "'"; IFS=" \t" env | cut -d'=' -f 1 | awk '{printf("${%s} ", $0);}'; echo -n "'";);

  echo "${_env} envsubst ${_envsubstDecl} < ${_file} > ${_output}" | sh;
  _rescode=$?;
  export RESULT="${_output}";
  return ${_rescode};
}

## Main logic
## dry-wit hook
function main() {
  replace_placeholders "${INPUT_FILE}" "${OUTPUT_FILE}";
}
# vim: syntax=sh ts=2 sw=2 sts=4 sr noet
1
Jose San Leandro

Utilisez cmakeconfigure_file une fonction.

Il copie un <input> fichier vers un <output> fichier et substitue les valeurs des variables référencées comme @VAR@ ou ${VAR} dans le contenu du fichier d'entrée. Chaque référence de variable sera remplacée par la valeur actuelle de la variable ou la chaîne vide si la variable n'est pas définie.

1
tml

De la même manière que pour la réponse Perl, la substitution de variable d'environnement peut être déléguée à la PHP CLI. Dépendance de PHP peut être acceptable ou non selon la pile technologique dans utilisation.

php -r 'echo preg_replace_callback("/\\$([a-z0-9_]+)/i", function ($matches) { return getenv($matches[1]); }, fread(STDIN, 8192));' < input.file > output.file

Vous pouvez aller plus loin et le mettre dans un script réutilisable, par exemple, envsubst:

#!/usr/bin/env php
<?php

echo preg_replace_callback(
    '/\$(?<name>[a-z0-9_]+)/i',
    function ($matches) {
        return getenv($matches['name']);
    },
    file_get_contents('php://stdin')
);

L'usage serait:

envsubst < input.file > output.file
0
Sergii Shymko