अपने वास्तविक मूल्यों के साथ एक फ़ाइल में पर्यावरण चर बदलें?


41

क्या फ़ाइल में पर्यावरण चर को प्रतिस्थापित / मूल्यांकन करने का एक आसान तरीका है? जैसे मान लें कि मेरे पास एक फ़ाइल config.xmlहै जिसमें शामिल हैं:

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

...आदि। मैं पर्यावरण चर $INSTANCE_IDके मान के साथ फाइल में प्रतिस्थापित करना चाहता हूं INSTANCE_ID, $SERVICE_NAMEजिसमें SERVICE_NAMEenv var का मान है । मुझे कोई प्राथमिकता नहीं पता होगी कि कौन से पर्यावरण संस्करण की आवश्यकता है (या इसके बजाय, मुझे स्क्रिप्ट को अपडेट करने की आवश्यकता नहीं है अगर कोई व्यक्ति कॉन्फ़िगर फ़ाइल में एक नया पर्यावरण चर जोड़ता है)। धन्यवाद!


1
जब आप फ़ाइल (कैट, इको, सोर्स,…) के साथ कुछ करेंगे तो वैरिएबल अपने मूल्य से घटाएगा
कोस्टा

क्या इस xml फ़ाइल की सामग्री आपके ऊपर है? यदि हां, तो पैरामीटर xslt मानों को इंजेक्ट करने का एक और तरीका प्रदान करता है और (envsubst और इसके ilk के विपरीत) एक परिणाम के रूप में अच्छी तरह से गठित xml की गारंटी देता है।
कोजिरो

जवाबों:


69

आप envsubst(का हिस्सा gnu gettext) का उपयोग कर सकते हैं :

envsubst < infile

आपकी संगत मान के साथ आपकी फ़ाइल में पर्यावरण चर को प्रतिस्थापित करेगा। चर नामों में केवल अल्फ़ान्यूमेरिक या अंडरस्कोर ASCII वर्ण शामिल होने चाहिए, न कि एक अंक से शुरू होने और गैर-रिक्त होने के लिए; अन्यथा इस तरह के एक चर संदर्भ को नजरअंदाज कर दिया जाता है।


केवल कुछ परिवेश चर को बदलने के लिए, इस प्रश्न को देखें।


1
... सिवाय इसके कि यह मेरी डॉक छवि में डिफ़ॉल्ट रूप से स्थापित नहीं है: '- (
रॉबर्ट फ्रेजर

4
अच्छी बात है। डॉकर छवियों को हल्का और दर्जी बनाया जाना चाहिए। बेशक, आप हमेशा इसे जोड़ सकते हैं, हालांकि।
कोजिरो

या उस पर पूर्ण कंटेनर जाओ और एक कंटेनर में सभी अपने आप में envsubst डाल दिया। यह एक सामान्य पैटर्न और जीवन का एक तरीका है यदि आप परमाणु होस्ट, कोरओएस या रैनचेरोस जैसे ओएस का उपयोग करते हैं। परमाणु विशेष रूप से फ़ाइल सिस्टम के साथ रूट गड़बड़ी नहीं होने देगा या जो स्थापित है उसे आपको कंटेनर का उपयोग करना होगा।
कुबेरचुन

1
ध्यान दें कि यह "सभी" पर्यावरण चर को प्रतिस्थापित नहीं करेगा, केवल उन लोगों को जिनके नाम ^[[:alpha:]_][[:alnum:]_]*$POSIX लोकेल में मेल खाते हैं ।
स्टीफन चेज़लस

लगता है बहुत रसीला है, लेकिन जरूरी नहीं कि सभी प्रतिस्थापन मूल्यों के साथ सही हो। यह XML विशेष वर्णों का सम्मान नहीं करता है।
EFraim

16

यह बहुत अच्छा नहीं है लेकिन यह काम करता है

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

यदि यह एक शेल स्क्रिप्ट में होता तो ऐसा दिखता:

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

संपादित करें, दूसरा प्रस्ताव:

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

संपादित करें, सख्ती से सवाल से संबंधित नहीं है, लेकिन फ़ाइल से पढ़े गए चर के मामले में:

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

इसके साथ समस्या यह है कि यदि फ़ाइल में एक पंक्ति है EOF, तो शेष पंक्तियों को शेल द्वारा कमांड के रूप में निष्पादित किया जाएगा। हम विभाजक को कुछ लंबे या अधिक जटिल में बदल सकते हैं, लेकिन अभी भी टकराव की एक सैद्धांतिक संभावना है। और कोई व्यक्ति जानबूझकर कमांड को निष्पादित करने के लिए विभाजक के साथ एक फ़ाइल बना सकता है।
ilkachachu

ठीक है, इसे आज़माएं: eval "echo \" $ (cat config.xml) \ ""
hschou

3
"; ls ;"फ़ाइल के अंदर कुछ डालने की कोशिश करें और उस evalकमांड को फिर से करें :) यह SQL इंजेक्शन के हमलों के साथ बहुत ही समस्या है। कोड के साथ डेटा मिक्स करते समय आपको वास्तव में सावधान रहना होगा (और यही शेल कमांड हैं), जब तक कि आप वास्तव में नहीं हैं , वास्तव में निश्चित रूप से कोई भी आपके दिन को गड़बड़ करने के लिए कुछ भी करने की कोशिश नहीं कर रहा है।
ilkachachu

नहीं "; ls;" कोई नुकसान नहीं करेगा।
hschou

3
@schou मुझे लगता है कि ilkkachu का मतलब था `"; ls ;"`- टिप्पणी का प्रारूप बैकटिक्स खा गया। लेकिन वास्तव में यह केवल `ls`यहाँ होना चाहिए । मुद्दा यह है कि फ़ाइल की सामग्री मनमाने ढंग से कोड निष्पादन की ओर ले जाती है और इसके बारे में आप कुछ नहीं कर सकते हैं।
गिल्स एसओ- बुराई को रोकना '

8

यदि आपके पास पर्ल (लेकिन गेटटेक्स्ट नहीं है envsubst) और आप एक छोटी स्क्रिप्ट के साथ सरल प्रतिस्थापन कर सकते हैं:

$ 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>

मैंने मान लिया कि चर नाम केवल अपरकेस अक्षर और अंडरस्कोर होंगे, लेकिन पहले पैटर्न को आवश्यकतानुसार बदलना आसान होना चाहिए। $ENV{...}पर्यावरण के संदर्भ में पर्ल देखता है।

यदि आप ${...}सिंटैक्स का समर्थन करना चाहते हैं या किसी अनसेट चर पर त्रुटि फेंकना चाहते हैं , तो आपको कुछ और काम करने की आवश्यकता होगी। के एक करीबी बराबर gettextकी envsubstहोगी:

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

हालांकि मुझे लगता है कि प्रक्रिया के माध्यम से उस तरह के चर खिलाते हुए वातावरण सामान्य रूप से थोड़ा iffy लगता है: आप फ़ाइलों में मनमाने ढंग से चर का उपयोग नहीं कर सकते हैं (क्योंकि उनके विशेष अर्थ हो सकते हैं), और कुछ मान संभवतः कम से कम अर्ध हो सकते हैं- उनमें संवेदनशील डेटा।


बल्कि पर्ल का उपयोग नहीं करेंगे क्योंकि यह डॉकटर कंटेनर माना जाता है, लेकिन यह सबसे अच्छा समाधान की तरह दिखता है।
रॉबर्ट फ्रेजर

2
perl -pe 's{\$(\{)?(\w+)(?(1)\})}{$ENV{$2} // $&}ge'केवल उन चरों को भी देखें जो परिभाषित हैं।
स्टीफन चेजलस

1

क्या मुझे इसके लिए अपनी खुद की स्क्रिप्ट का सुझाव देना चाहिए?

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

0

पर्ल जवाब के समान, पर्यावरण चर प्रतिस्थापन को PHP सीएलआई में सौंपा जा सकता है। उपयोग पर टेक स्टैक के आधार पर PHP पर निर्भरता स्वीकार्य हो सकती है या नहीं भी हो सकती है।

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

आप आगे जा सकते हैं और इसे पुन: प्रयोज्य स्क्रिप्ट में रख सकते हैं, उदाहरण के लिए 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')
);

उपयोग होगा:

envsubst < input.file > output.file
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.