0

I've been trying to evaulate an expression inside a function as follows:

eval "fn() { $(cat fn.sh); }"

Where fn.sh contains the following:

#!/bin/sh
echo "You provided $1."

So that when I call:

fn "a phrase"`

it prints "You provided a phrase.". However I cannot get it to work.

What's particularly frustrating is that:

eval "$(cat fn.sh)"

works perfectly! What am I missing here?

What I've tried:

eval "fn() { \"\$(cat fn.sh)\"; }"
fn
# bash: #!/bin/sh
# echo "You provided $1."
# return 1: No such file or directory

eval "fn() { \$(cat fn.sh); }"
fn
# bash: #!/bin/sh: No such file or directory

and myriad other combinations, most of which at this point is guess work.

Nick Bull
  • 9,518
  • 6
  • 36
  • 58
  • Why aren't you just defining the function in `fn.sh` and simply sourcing it? Using `eval` just opens a security hole for no perceived benefit. – chepner Sep 17 '18 at 14:17
  • @chepner The benefit is dynamic function names. If somebody has write access of any sort to these scripts I'll be pretty screwed anyway; they don't take input. Thank you for your concern regarding security however, I acknowledge the flaws of eval – Nick Bull Sep 17 '18 at 14:19
  • PS: I know the example does take input, but it is only an example – Nick Bull Sep 17 '18 at 14:20
  • Hey @chepner, I found the answer. I'd be very happy if somebody with a bit more experience, such as yourself, could comment explaining or referencing material that explains the security risks associated with `eval`. I don't want to encourage bad practice! – Nick Bull Sep 17 '18 at 14:33
  • 1
    Side note: the hashbang line in `fn.sh` won't do anything, it'll just be ignored as a comment. – Benjamin W. Sep 17 '18 at 14:36
  • Thank you for explaining that explicitly Benjamin :) – Nick Bull Sep 17 '18 at 14:37
  • Just define a function in the source file, and wrap it in another function or use an alias if you want another name. Don't look for reasons to use `eval`. – chepner Sep 17 '18 at 14:38
  • @chepner I disagree with the sentiment from what I've read. I agree `eval` is very dangerous if used poorly, but I think there's no greater risk using `eval` than using any other command when used properly. I think the answers below, especially Benjamin's comment, are well formatted, especially considering my use case is a local script only on a single-user machine. If you could maybe show me a security exploit I'd be happy to acknowledge it. – Nick Bull Sep 17 '18 at 14:39
  • Not really, the version from my comment is still vulnerable to injection. If `fn.sh` contains something like `:; } echo "evil command" #` that will declare `fn` as a no-op (containing just `:`) and then run the evil command. – Benjamin W. Sep 17 '18 at 17:01

2 Answers2

0

Found the answer:

eval "fn() { eval \"\$(cat "fn.sh")\"; }"

Mandatory reference that explains to the best degree I understand the security risks of using eval.

Nick Bull
  • 9,518
  • 6
  • 36
  • 58
0

Just use source/. from inside the new function.

fn () {
  . fn.sh "$1"
}

If the function is used often enough where you think repeated disk I/O would be an issue, the file will almost certainly be in a disk cache when you call fn.

chepner
  • 497,756
  • 71
  • 530
  • 681