5

All that I really want to do is make sure everything in a pipeline succeeded and assign the last stdin to a variable. Consider the following dumbed down scenario:

x=`exit 1|cat`

When I run declare -a, I see this:

declare -a PIPESTATUS='([0]="0")'

I need some way to notice the exit 1, so I converted it to this:

exit 1|cat|xargs -I {} x={}

And declare -a gave me:

declare -a PIPESTATUS='([0]="1" [1]="0" [2]="0")'

That is what I wanted, so I tried to see what would happen if the exit 1 didn't happen:

echo 1|cat|xargs -I {} x={}

But it fails with:

xargs: x={}: No such file or directory

Is there any way to have xargs assign {} to x? What about other methods of having PIPESTATUS work and assigning the stdin to a variable?

Note: these examples are dumbed down. I'm not really doing an exit 1, echo 1 or a cat, but used these commands to simplify so we can focus on my particular issue.

6 Answers 6

3

When you use backticks (or the preferred $()) you're running those commands in a subshell. The PIPESTATUS you're getting is for the assignment rather than the piped commands in the subshell.

When you use xargs, it knows nothing about the shell so it can't make variable assignments.

Try set -o pipefail then you can get the status from $?.

Sign up to request clarification or add additional context in comments.

1 Comment

pipefail is a good option to consider. However, I wish I could get teh PIPESTATUS for everything in the pipeline.
3

xargs is run in a child process, as are all the commands you call. So they can't effect the environment of your shell.

You might be able to do something with named pipes (mkfifo), or possible bash's read function?

EDIT:

Maybe just redirect the output to a file, then you can use PIPESTATUS:

command1 | command2 | command3 >/tmp/tmpfile
## Examine PIPESTATUS
X=$(cat /tmp/tmpfile)

1 Comment

I was thinking read could do something like that. echo 1|read x didn't work. Do you have an example?
0

How about ...

read x <<<"$(echo 1)"
read x < <(echo 1)

echo "$x"

1 Comment

Interesting thought. Using (exit 1|cat) still doesn't properly populate PIPESTATUS.
0

Why not just populate a new array?

IFS=$'\n' read -r -d '' -a result < <(echo a | cat | cat; echo "PIPESTATUS='${PIPESTATUS[*]}'" )
IFS=$'\n' read -r -d '' -a result < <(echo a | exit 1 | cat; echo "PIPESTATUS='${PIPESTATUS[*]}'" )

echo "${#result[@]}"
echo "${result[@]}"
echo "${result[0]}"
echo "${result[1]}"

Comments

0

There are already a few helpful solutions. It turns out that I actually had an example that matches the question as framed above; close-enough anyway.

Consider this:

 XX=$(ls -l *.cpp | wc -l  | xargs -I{} echo {})
 echo $XX
 3

Meaning that I had 3 x .cpp files to in my working directory. Now $XX is 3 and I can make use of that result in my script. It is contrived, because I don't actually need the xargs in this example. It works though.

In the example from the question ...

x=`exit 1|cat`

I don't think that will give you what was specified. exit will quit the sub-shell before the cat gets a mention. Also on that note,

I might start with something like

declare -a PIPESTATUS='([0]="0")'
x=$?

x now has the status from the last command.

Comments

0

Assign each line of input to an array, e.g. all python files in a directory

declare -a pyFiles=($(ls -l *.py | awk '{print $9}')) 

where $9 is the nineth field in ls -l corresponding to the filename

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.