Reputation: 220
Let's say I have a file.txt file like this:
some words
from here
blah blah blah
that begins
this is this
to here
other content
and another file called *config.conf" like this:
name1:value1
name2:value2
expr:sed -re "s/this/that/g" -ne "/from here/,/to here/ p"
name3:value3
name4:value4
In my script.sh I need to get the whole sed command that is written after "expr:" in the config.conf and execute it in a pipe like this :
#!/bin/bash
pipecommand=$(cat info | grep -e "^expr:" | sed -re "s/^expr://g")
cat file.txt | $pipecommand > output.file
but I get this error:
sed: -e expression #1, char 1: unknown command: `"'
I've read about many similar questions here and the solution was using an array like this:
pipecommand=($(cat info | grep -e "^expr:" | sed -re "s/^expr://g"))
cat file.txt | ${pipecommand[@]} > output.file
Unfortunately this works only with less complex commands and only if I assign the "sed...blah blah blah" command directly to the variable, without reading it from a file.
Do some of you know a working solution to this?
P.S.: I can change both the script.sh and the config.conf files.
Upvotes: 2
Views: 388
Reputation: 295490
Interpreting this as a question about how to apply the advice from Reading quoted/escaped arguments correctly from a string to your use case:
#!/usr/bin/env bash
# the sed expression here is modified to work with BSD sed, not only GNU sed
pipecommand=$(sed -ne 's/^expr://p' <info)
array=( )
while IFS= read -r -d ''; do
array+=( "$REPLY" )
done < <(xargs printf '%s\0' <<<"$pipecommand")
<file.txt "${array[@]}" > output.file
This safer than eval
, insofar as the words inside your expr:
can be treated only as literal arguments, and can't be parsed as redirections, substitutions, parameter expansions, or other shell syntax. Of course, an expr of sh -c '...'
can be used to enable shell syntax inside the ...
section: Constraining the command (the first element of the array) is necessary if you genuinely wanted to sandbox, control or constrain the invoked command.
Upvotes: 3
Reputation: 531325
Turn your config file into a plugin with a well-defined interface. Here, your script expects a function named sed_wrapper
, so you provide a definition with that name in your "config file" (renamed to lib.sh
here).
# This is lib.sh
sed_wrapper () {
sed -re "s/this/that/g" -ne "/from here/,/to here/ p"
}
Then, in your script, call the named function.
. lib.sh
sed_wrapper < file.txt > output.file
Upvotes: 2
Reputation: 141155
Sadly, you need eval.
pipecommand=$(grep "^expr:" info | cut -d: -f2-)
eval "$pipecommand" <file.txt > output.file
Try to avoid eval.
Upvotes: 2