Some possibilities that produce a single output file.
Option 1 - redirect stdout
and stderr
to separate files, then remove empty files:
php file.php > ./data.csv 2> ./error.txt
[[ ! -s ./data.csv ]] && rm ./data.csv
[[ ! -s ./error.txt ]] && rm ./error.txt
The ! -s
test will be true if a file is zero-length. This version uses some fairly common shell idioms, and should work in both zsh
and bash
. The operations can be combined into a function:
phpPost() {
php ${1:?script required} > ${2:?csv required} 2> ${3:?err required}
[[ ! -s $2 ]] && rm $2
[[ ! -s $3 ]] && rm $3
}
phpPost file.php data.csv error.txt
Option 2 - save stdout
and stderr
in shell variables, and only create the files if there is output:
php file.php \
> >(d=$(<&0) && [[ -n $d ]] && <<<$d >data.csv) \
2> >(e=$(<&0) && [[ -n $e ]] && <<<$e >error.txt)
Some of the pieces:
>
, 2>
- redirect stdout
and stderr
.
>(...)
- process substitution. The shell creates a subprocess (sort of - see below) and sends the output that we've redirected to that process.
t=$(<&0)
- store the stdin
of the subprocess in the variable t
.
[[ -n ... ]]
- test if the string is non-empty.
<<<... > ...
- use a here-string to write the variable contents to a file.
This version comes with some caveats:
- It is specific to
zsh
(or more accurately, it did not work in my very brief tests with bash
).
- This is not a common shell idiom.
- The files are not overwritten each time.
- Process substitutions can be run asynchronously by the shell, which means in some cases the initial command might finish before the output files are completely written. In this instance, the commands within the process substitution are all
zsh
built-ins, so the shell runs them synchronously within a single process. Other variations of this pattern might behave differently - the zsh documentation describes a workaround if that is an issue.
This can also be written as a function:
phpVars() {
rm ${2:?} ${3:?} 2>/dev/null
php ${1:?} \
> >(d=$(<&0) && [[ -n $d ]] && <<<$d >${2}) \
2> >(e=$(<&0) && [[ -n $e ]] && <<<$e >${3})
}
phpVars file.php data.csv error.txt
Alternative solutions:
- It may be easier to detect whether the
php
command succeeded by testing the shell return code instead of looking at the output files.
- If updating the
php
code is a possibility, that script could write directly to the data and error files instead of passing the information through the shell.