shell script replace variables in file - error with Sed's -i option for in-place updating

前端 未结 3 1055
一生所求
一生所求 2020-12-04 00:28

Here is my test.env

RABBITMQ_HOST=127.0.0.1
RABBITMQ_PASS=1234

And I want to use test.sh to replace the value in

3条回答
  •  盖世英雄少女心
    2020-12-04 01:23

    Simple Case

    If test.env contains only the two variables, you can simply create a new file, or overwrite existing:

    printf "RABBITMQ_HOST=%s\nRABBITMQ_PASS=%s\n" \
      "${RABBITMQ_HOST}" "${RABBITMQ_PASS}" > "$Deploy_path"
    

    Fixing Unquoted Variables and Optimizing the SED Commands

    Try to fix your command as follows:

    sed -i -e 's/\(RABBITMQ_HOST=\).*/\1'"$RABBITMQ_HOST"'/' \
      -e 's/\(RABBITMQ_PASS=\).*/\1'"$RABBITMQ_PASS"'/' \
      "$Deploy_path"
    

    You should enclose the variables in double quotes, since otherwise the shell will interpret the contents. In a content in double quotes, the shell will interpret only $ (replacing the variable with its content), backquote, and \ (escape). Also note the use of multiple -e options.

    Why SED is Bad for this Task (in my Opinion)?

    But, as it is said in @mklement0's answer, -i might not work in this form on BSD systems. Also, the command only modifies the two variables, if they are defined in $Deploy_path file, if the file exists. It will not add new variables into the file. Be warned, the variables are embedded directly into the replacement, and their values, generally, should be escaped according to the SED rules!

    Alternative

    If the test.env file is trusted, I recommend to load the variables, modify them and print to the output file:

    (
      # Load variables from test.env
      source test.env
    
      # Override some variables
      RABBITMQ_HOST=rabbitmq1
      RABBITMQ_PASS=12345
    
      # Print all variables prefixed with "RABBITMQ_".
      # In POSIX mode, `set` will not output defines and functions
      set -o posix
      set | grep ^RABBITMQ_
    ) > "$Deploy_path"
    

    Consider adjusting the file system permissions for test.env. I suppose, the source file is a trusted template.

    The solution without SED is better, in my opinion, because the SED implementations may vary, and the in-place option may not work as expected on different platforms.

    But, isn't source risky?

    While parsing the shell variable assignments is usually an easy task, it is more risky than just sourcing the ready-for-use "script" (test.env). For instance, consider the following line in your test.env:

    declare RABBITMQ_HOST=${MYVAR:=rabbitmq1}
    

    or

    export RABBITMQ_HOST=host
    

    All of the currently suggested solutions, except the code using source, assume that you assign the variable as RABBITMQ_HOST=.... Some of the solutions even assume that RABBIT_HOST is placed at the beginning of the line. Ahh, you might fix the regular expression then, right? Just for this case...

    Thus, source is risky as much as the file being sourced is not trusted. Think of #include in C, or include "file.php" in PHP. These instructions include the source into the current source as well. So don't blindly consider sourcing a file as anti-pattern. It all depends on the particular circumstances. If your test.env is a part of your repository being deployed, then it is surely safe to call source test.env. That's my opinion, however.

提交回复
热议问题