简体   繁体   中英

Bash Getting variables from a file safely

I have a script that stores variables inside a .txt file for later use. I want to retrieve those variables from the file safely.

How I have it setup now:

Settings.txt

var1=value1
var2=value2
...

Script

for i in $(cat Settings.txt); do $i done
# So now "var1" has the value "value1", and so on

This works, but is dangerous, as someone could inject code trough that txt file.

I know about the source command, but that too has the same problem. So, how to achieve the same functionality safely?

If you don't want separate steps for validation and variable creation:

Update, based on declare : A simpler approach that is still safe is to use the declare builtin to define the variables:

#!/usr/bin/env bash

# Read the file line by line.
while read -r line; do
  declare -- "$line"
done <<'EOF'
  var1=value1
  var2=value2
EOF
  • The declare command fails with input lines that aren't valid shell variable assignments, but it fails safely in that the line is never evaluated as a command .

  • Note that the values are read as literals , exactly as defined in the file (except for removal of trailing whitespace).

  • If you also want to support single- or double-quoted values, use the following declare command instead:
    declare -- "$(xargs -I {} printf %s {} <<<"$line")"
    but note that using embedded, escaped quotes of the same type in values is not supported (this is a limitation of xargs ).


Original answer, based on printf -v :

#!/usr/bin/env bash

# Read the file line by line.
while read -r line; do
  # Split the line into name and value using regex matching.
  if [[ $line =~ ^([^=]+)=(.*)$ ]]; then
    # ${BASH_REMATCH[1]} now contains the variable name, 
    # ${BASH_REMATCH[2]} the value.
    # Use printf -v to store the value in a variable.
    printf -v "${BASH_REMATCH[1]}" %s "${BASH_REMATCH[2]}"
  fi
done <<'EOF'
  var1=value1
  var2=value2
EOF

# Print the variables that were created (based on name prefix `var`).
for name in ${!var*}; do
  printf '%s=%s\n' "$name" "${!name}"
done
  • Note that the values are read as literals , exactly as defined in the file (except for removal of trailing whitespace).

    • If there are values that are single- or double-quoted and you want to remove the quotes, use the following printf -v command instead:
      printf -v "${BASH_REMATCH[1]}" %s "$(xargs -I {} printf %s {} <<<"${BASH_REMATCH[2]}")"
      but note that quoted strings with embedded, escaped quotes of the same type are not supported.
  • Should be safe to use, because printf -v is used to create the variables - the shell doesn't directly source the assignment statements, which is where injection could happen.

  • Lines not recognized as variable assignments are simply skipped.

  • Regex ^([^=]+)=(.*)$ matches any line that starts with ( ^ ) a least 1 ( + ) character other than = ( [^=] ), followed directly by = , followed by any remaining sequence of characters ( .* ) through the end of the line ( $ ). The parentheses around ([^=]+) and (.*) ensure that the captured substrings are saved in special Bash array variable ${BASH_REMATCH[@]} , starting at index 1.

    • For simplicity, no attempt is made to validate the variable name up front, which means that the printf -v command may fail later.

You can check variables assignments format before sourcing :

#!/bin/bash

file=Settings.txt
regex_varname='^[a-zA-Z0-9_]\+\'
regex_varvalue='[a-zA-Z0-9]\+$'

is_safe_var() {
  while read var; do
    grep -q $regex_varname=$regex_varvalue <<< "$var" || return 1
  done < "$file"
}

is_safe_var && source "$file" || echo "Break"

The variables $regex_varname and $regex_varvalue are assigned patterns for variables authorized name and value :

  • ^[a-zA-Z0-9_] : variable name beginning with one or more alphanumeric character or _
  • [a-zA-Z0-9]\\+$ : variable value ending with one or more alphanumeric character

The loop in function is_safe_var checks for each line of Settings.txt if variables assignments match the pattern $regex_varname=$regex_varvalue .

If one line fails the test, it returns from function with error code and echo "Break" , otherwise Settings.txt is sourced.

Note : you may complete the character range [a-zA-Z0-9_] and [a-zA-Z0-9] with authorized characters in your variables names and values.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM