1

I want to read the following variables from a data file in bash.

#/tmp/input.dat
$machie=1234-567*890ABC
$action=REPLACE
$location=test_location

Thanks for your help.

Tas

3
  • Do you control the input format? Commented Apr 17, 2018 at 22:26
  • @CharlesDuffy yes, I do. Commented Apr 17, 2018 at 22:41
  • 1
    If you didn't have the leading $s, your input file would be a valid shell script, so you could source /tmp/input.dat to execute it in the current interpreter. Of course, this means you need to trust its contents to not do anything malicious (even unintentionally!) when parsed in this way; it would be safer to generate it with code that knows how to do proper shell escaping if it's not hand-written by a human who knows the pertinent rules. Commented Apr 17, 2018 at 22:43

1 Answer 1

4
#!/usr/bin/env bash
case $BASH_VERSION in
  ''|[0-3].*) echo "ERROR: Bash 4.0 or newer is required" >&2; exit 1;;
esac

# read input filename from command line, default to "/tmp/input.dat"
input_file=${1:-/tmp/input.dat}

declare -A vars=()

while IFS= read -r line; do
  [[ $line = "#"* ]] && continue  # Skip comments in input
  [[ $line = *=* ]]  || continue  # Skip lines not containing an "="
  line=${line#'$'}                # strip leading "$"
  key=${line%%=*}                 # remove everything after first "=" to get key
  value=${line#*=}                # remove everything before first "=" to get value
  vars[$key]=$value               # add key/value pair to associative array
done <"$input_file"

# print the variables we read for debugging purposes
declare -p vars >&2

echo "Operation is ${vars[action]}; location is ${vars[location]}" >&2

See:

  • BashFAQ #1 - How can I read a file (data stream, variable) line-by-line (and/or field-by-field)?
  • BashFAQ #6 - How can I use variable variables (indirect variables, pointers, references) or associative arrays?; here, we're using associative arrays, but you could use the same technique to assign directly to named variables.[1]
  • Parameter expansion, the syntax used for isolating the "key" and "value" sections of each line; also covered in BashFAQ #100.

[1] - Note that if you aren't going to use associative arrays, as suggested in this answer, for security reasons it's best to use a prefixed namespace: printf -v "var_$key" %s "$value" -- generating variable names you would dereference as $var_action or $var_location -- is much safer than printf -v "$key" %s "$value", as the former ensures that your data file can't overwrite a security-critical environment variable such as PATH or LD_PRELOAD, by way of causing such attempts to harmlessly set $var_PATH or $var_LD_PRELOAD.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.