问题
Given a pipeline something like "A|B|C|D|E", I want to make step C conditional on the result of step B. Something like this:
A | B | if [ $? -ne 0 ]; then C; else cat; fi | D | E
But this doesn't seem to work; C is never executed no matter what the result of B. I'm looking for a better solution.
I understand that each step of a pipeline runs in its own subshell. So I can't pass an environment variable back to the pipeline. But this pipeline is in a Gnu Parallel environment where many such pipelines are running concurrently and none of them knows any unique value (they just process the data stream and don't need to know the source, the parent script handles the necessary separation). That means that using a temporary file isn't practical, either, since there isn't any way to make the file names unique. Even $$ doesn't seem to give me a value that is the same in each of the steps.
回答1:
You can't make a pipeline conditional because the commands are run in parallel. If C
weren't run until B
exited, where would B
's output be piped to?
You'll need to store B
's output in a variable or a temporary file. For instance:
out=$(mktemp)
trap 'rm "$out"' EXIT
if A | B > "$out"; then
C < "$out"
else
cat "$out"
fi | D | E
回答2:
There is a logical impossibility in the way you state the problem.
Suppose a pipe like A | B
. The pipeline exists specifically because we want B to begin reading from A before A finishes. So when B starts (which would be when your condition is evaluated), A does not yet know if it will fail or succeed, so B cannot know either.
What you can do, is have A echo, as its last line, some type of status code. Then B can read from standard in, save the input (either as a temporary file, into a variable), and then once the last line is received, check the status and then take action.
The other way to do it, of course, is have A store its own output, and then as it finishes, have the conditional inside A (and eliminate B from the pipeline).
来源:https://stackoverflow.com/questions/41708783/conditional-step-in-a-pipeline