0

So I have a question. I managed to go get this to work below.

main () {
  file="$1"
  if [ ! -e "$file" ]; then echo "$2" > $1; fi
}

main /var/store/traefik.provider NOT-SET
main /var/store/server.email NOT-SET
main /var/store/traefik.domain NOT-SET
main /var/store/tld.program NOT-SET

# Recall Variables - tld - provider - domain - email
provider=$(cat /var/store/traefik.provider)
tld=$(cat /var/store/tld.program)
domain=$(cat /var/store/traefik.domain)
email=$(cat /var/store/server.email)

In reality, I'm trying to make code work like this by adding a $3. The problem I run into that I cannot store a variable into $3. I get:

provider=NOT-SET: command not found

As you can see below, I'm trying to recall a variable and store it into the $3 so it's not lengthy up top. Would you have any suggestions?

main () {
  file="$1"
  if [ ! -e "$file" ]; then echo "$2" > $1; fi
  $3=(cat $2)
}

main /var/store/traefik.provider NOT-SET provider
main /var/store/server.email NOT-SET email
main /var/store/traefik.domain NOT-SET domain
main /var/store/tld.program NOT-SET program
0

4 Answers 4

3

Assuming that you really want to create a file with NOT-SET, try one of these:

main() {
   local file=$1 val=$2 var=$3
   [[ -e $file ]] || printf '%s\n' "$val" > "$file"
   printf -v "$var" '%s' "$(<"$file")"
}

main /var/store/traefik.provider NOT-SET provider

main() {
   local file=$1 val=$2
   [[ -e $file ]] || printf '%s\n' "$val" > "$file"
   cat "$file"
}

provider=$(main /var/store/traefik.provider NOT-SET)
Sign up to request clarification or add additional context in comments.

3 Comments

Don't use parameter expansion as the first argument to printf, as it won't behave as you expect if it contains a %. Use the explicit form printf -v "$var" '%s' "$var" ... instead.
@chepner You are absolutely right, I missed that. Thanks!
The first one worked beautifully. I struggled with this for awhile. I have tons of redundant code and this is a huge time saver! thank you!
1
$3=(cat $2)

This is invalid. This is wrong syntax. See, the part before = is interpreted as variable name and is not expanded. A variable name cannot start with $.

There maybe many solutions to your problem, bad ones using eval and good ones using other techniques.

Grab a good solution:

main() {
  declare -n ref="$3"
  if [ ! -e "$1" ]; then 
     echo "$2" > "$1";
     ref=$2
  fi
}

Now the magic is in -n switch to declare command. From declare --help:

-n  make NAME a reference to the variable named by its value

So what happens here, bash interprets the variable value to be a reference to other variable. Thus ref=$2 automagically set's the variable name $3 to the value of $2.

Let's do a bad solution:

main() {
  if [ ! -e "$1" ]; then 
     echo "$2" > "$1";
     eval "$3=\$2"
  fi
}

Let's remember that eval is evil. What happens here, is that "$3=\$2" is double evaluated, once when passing to eval, so it becomes <the string behind $3>=$2, then it get's evaluated second time setting the variable.

2 Comments

You could also mention that namerefs require bash 4.3 or later :)
printf -v "$3" '%s' "$2" is the safest option. Namerefs are an improvement over eval, but aren't bulletproof. See Bash FAQ 048
1

You just need a way to fix the syntax. You could use an eval, though a printf -v is better.

$: cat settst
#! /bin/bash
(( $# )) || { echo $0 var val; exit 1; }
setting() {
  eval $1=$2
  printf -v "$2" "%s" "$1"
}
setting $1 $2
set|grep $1=$2
set|grep $2=$1

$: settst foo bar
foo=bar
bar=foo
$: settst x y
x=y
y=x

$3=... isn't generally valid syntax. By using eval that becomes the value of $3 followed by the =, which will be a valid assignment if $3's value is a valid variable name. The printf -v, on the other hand, explicitly writes the value to a variable named.

Use the printf -v "$var" '%s' "$(<"$file")" syntax mickp offered, but eval will do the job. It will just come back to bite you eventually.

Comments

0

$3 is the third positional parameter in script context the third argument used to call script, in a function the third argument.

Two options:

  • make the logic outside main function to add a third argument to main
  • or use set inside the function to set arguments set -- "$1" "$2" "$(<"$2")"

Note: once file variable assigned with $1 do not use $1 any more but use "$file"

echo "$2" > "$file"

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.