问题
I am writing a bash program that takes options.
For example : ./my_program -l 3 -a -s
-l 3
will limit the output to three lines-a
will select all my file-s
will sort the output
For now, I could use two options at a time this way:
if [ $all == 1 ]
then
if [ $sort == 1 ]
then
printf '%s\n' "${haikus[@]}" | sed -e 's/^[ \t]*//' | sort
else
printf '%s\n' "${haikus[@]}" | sed -e 's/^[ \t]*//'
fi
fi
If -a
option, I print the whole file, or, if -a
option and -s
option, I use the same command but i use sort
.
With this solution, if I want to implement the -l
, it would create a lot of "if" statements.
I first thought of creating a variable containing my command.
Example:
sort='sort'
limit='grep -m3'
and then write my command this way:
printf '%s\n' "${haikus[@]}" | sed -e 's/^[ \t]*//' | $sort | $limit
But that is simply not working.
The fact is, I would like to write a basic command, and being able to add more to this one, depending of the options.
How can I do this properly without tons of "if" statements?
回答1:
Great question with a tricky, not-so-obvious solution.
What you can do is chain together a couple of function calls. Those functions can examine the relevant flags and then either "do something" like call sort
or "do nothing" and simply call cat
. A plain cat
call in a pipeline is essentially a no-op: it copies stdin to stdout unchanged.
maybe_sort() {
if [[ $sort == 1 ]]; then
sort
else
cat
fi
}
maybe_limit() {
if [[ -n $limit ]]; then
head -n "$limit"
else
cat
fi
}
To use these you'd then write:
printf '%s\n' "${haikus[@]}" | sed -e 's/^[ \t]*//' | maybe_sort | maybe_limit
回答2:
You can pipe directly to an if
statement. This will require a no-op filter like cat
, though, in some places, so it is slightly less efficient in that regard.
printf '%s\n' "${haikus[@]}" | sed -e 's/^[ \t]*//' |
if [ "$sort" = 1 ]; then sort; else cat; fi |
if [ "$l" -gt 0 ]; then grep -m"$l"; else cat; fi
An if
statement is itself a command, so it has its own sets of file descriptors that the enclosed commands inherit. The if
statement itself doesn't do anything with those descriptors, so sort
and cat
both see the data they would if they hadn't been wrapped in the first place.
回答3:
Ok everyone. I'm replying a bit late. I didn't know I could use cat as a no-op, and that was the solution I sought. So I simply initialized all my options with "cat" op. If the option is triggered correctly, I simply update the string with the good op. Then, I just had to write one op line, with all options in it.
Thank you a lot.
来源:https://stackoverflow.com/questions/52538881/dynamically-building-a-command-pipe-in-bash