Run a bash array with pipes

How to run a command line from a bash array containing a pipeline?

For example, I want to run ls | grep x ls | grep x with:

 $ declare -a pipeline $ pipeline=(ls) $ pipeline+=("|") $ pipeline+=(grep x) $ "${pipeline[@]}" 

But I get this:

 ls: cannot access |: No such file or directory ls: cannot access grep: No such file or directory ls: cannot access x: No such file or directory 
+4
source share
3 answers

Short form: you cannot (without writing code), and this is a function, not an error.

If you do something in a safe way, you protect your data from analysis as code (syntax). However, you clearly want to treat the data here as code, but only in a controlled way.

What you can do is iterate over the elements, use printf '%q ' "$element" to get a safe-quoting string if they are not a pipeline, and leave them unnoticed if they are.

After that and ONLY after that you can safely evaluate the output string.

 eval_args() { local outstr='' while (( $# )); do if [[ $1 = '|' ]]; then outstr+="| " else printf -v outstr '%s%q ' "$outstr" "$1" fi shift done eval "$outstr" } eval_args "${pipeline[@]}" 
By the way, this is much safer than doing this. Think about where you are processing the list of files, and one of them is called | ; this strategy can be used by an attacker to inject code. Using separate lists for arrays before and after, or creating only one side of an array pipeline and hard coding the other, is much better.
+4
source

Close - just add eval :

 $ eval ${pipeline[@]} 
+1
source

This works for me:

 bash -c "${pipeline[*]}" 
0
source

Source: https://habr.com/ru/post/1485116/


All Articles