2

I am currently working with a bash script that passes variables to some legacy code using text files.

The script sets the values of the variables some some legacy program (lp) by 1) creating variables with the prefix lp_ and 2) and then saving the values of these parameters as a text file in lp_run_directory. Here's a sample file:

#!/bin/bash

#Set the parameters here
lp_parameter_a=(0.2 0.4 1)
lp_parameter_b="TRUE"
lp_parameter_c=0

#Set the working directory here (put pwd for generality)
lp_run_directory=$(pwd)"/"

#Write parameter values in the directory
echo ${lp_parameter_a[@]} > $lp_run_directory"parameter_a.txt"
echo ${lp_parameter_b[@]} > $lp_run_directory"parameter_b.txt"
echo ${lp_parameter_c[@]} > $lp_run_directory"parameter_c.txt"

#Run program that depends on parameter values here...


lp_run_directory ="/users/ss/"
echo ${lp_parameter_a[@]} > lp_run_directory"parameter_a.txt"
echo ${lp_parameter_b[@]} > lp_run_directory"parameter_b.txt"

This works fine, but involves a lot of hardcoded text. I'm wondering if someone can help me define a function that can automate this in some way.

I'm not sure about what is possible in bash, but an ideal solution would be a function that takes the names of all of the variables in my workspace that begin with lp_ and then saves all of them to lp_run_directory.

4
  • 1
    Look up variable indirection in the bash documentation. Commented Jun 7, 2014 at 1:14
  • Can you post a sample file? Commented Jun 7, 2014 at 2:07
  • lp_parameter_b and lp_parameter_c are not arrays; why are you indexing them like they are? Commented Jun 7, 2014 at 4:11
  • @chepner That's true. I did it this way because it allows me to change lp_parameter_b/lp_parameter_c between scalar values or arrays at the top of the file without having to change the "writing to text" that's going on at the bottom of the file. Commented Jun 7, 2014 at 4:54

1 Answer 1

2

Here's a bash function that takes an output dir. and a variable prefix as its arguments and outputs each matching variable's value into a file named for the variable (sans prefix) in the output dir.

varsToFiles() {  

  local outDir=$1 prefix=$2 name fname rest isArray

  while IFS='=' read -r name rest; do
    # Determine the output filename - the variable name w/o prefix.
    fname=${name#$prefix}
    # Determine if the variable is an array.
    [[ $(declare -p "$name" | cut -d' ' -f2) == *a* ]] && isArray=1 || isArray=0
    (( isArray )) && name="$name[@]"
    # Output var. value and send to output file.
    echo "${!name}" > "$outDir/$fname"
  done < <(shopt -so posix; set | egrep "^${prefix}[^ =]*=")

}

# Invoke the function.
varsToFiles '/users/ss' 'lp_'

Note:

  • As in the question, elements of array variables are output simply with echo, so that the partitioning into individual elements is lost in case of elements with embedded whitespace (this could easily be fixed).

The input to the while loop:

  • shopt -so posix; set prints all variables and their values; shopt -so posix ensures that only variables are printed and not also functions.
  • egrep "^${prefix}[^ =]*=" filters the output down to variables whose names start with the specified prefix.

The while loop:

  • while IFS='=' read -r name rest loops over all input lines and parses them into the variable name (and the rest of the line, which is not otherwise used in this function).
  • fname=${name#$prefix} determines the output filename by stripping the prefix from the variable name using bash's parameter expansion.
  • [[ $(declare -p "$name" | cut -d' ' -f2) == *a* ]] determines if the variable at hand is an array variable or not - declare -p outputs a as part of the 2nd field for arrays.
  • (( isArray )) && name="$name[@]": array variables: an additional indirection step is required beforehand in order to output all array elements at once: the all-elements subscript [@] is appended to the name first, and then variable indirection is performed in the next step.
  • echo "${!name} echoes each matching variable's value using bash's variable indirection and send the output to the output file (> "$outDir/$fname")
Sign up to request clarification or add additional context in comments.

3 Comments

Thanks! Two questions: 1) For array variables, the function prints the array as it should in the text file, but the file name has a "[@]" at the end; 2) Is there a way to strip "prefix" from the name of text file name (so that the variable "lp_parameter_a" is printed into "$outDir/"'parameter_a'
Awesome. This works great. Thanks so much for explaining what everything did!
@BerkU. My pleasure; I'm glad to hear it.

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.