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

4 Answers4

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)
mickp
  • 1,679
  • 7
  • 23
  • 1
    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 Nov 08 '18 at 13:47
  • @chepner You are absolutely right, I missed that. Thanks! – mickp Nov 08 '18 at 13:49
  • 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! – Admin9705 Nov 08 '18 at 23:10
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.

KamilCuk
  • 120,984
  • 8
  • 59
  • 111
  • You could also mention that `nameref`s require `bash` 4.3 or later :) – mickp Nov 08 '18 at 13:13
  • 1
    `printf -v "$3" '%s' "$2"` is the safest option. Namerefs are an improvement over `eval`, but aren't bulletproof. See [Bash FAQ 048](https://mywiki.wooledge.org/BashFAQ/048#The_problem_with_bash.27s_name_references) – chepner Nov 08 '18 at 13:46
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.

Paul Hodges
  • 13,382
  • 1
  • 17
  • 36
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"
Nahuel Fouilleul
  • 18,726
  • 2
  • 31
  • 36