6

I'm trying to run a command, write that to a file, and then I'm using that file for something else.

The gist of what I need is:

myAPICommand.exe parameters > myFile.txt

The problem is that myAPICommand.exe fails a lot. I attempt to fix some of the problems and rerun, but I get hit with "cannot overwrite existing file". I have to run a separate rm command to cleanup the blank myFile.txt and then rerun myAPICommand.exe.

It's not the most egregious problem, but it is annoying.

How can I avoid writing a blank file when my base command fails?

  • 1
    How is failure indicated? A return code? An empty file? – Jeff Schaller Dec 17 '18 at 14:52
  • @JeffSchaller error is written to the command line, in this case. – goodguy5 Dec 17 '18 at 18:33
  • "command-line" meaning redirected to myFile.txt as "stdout", or to the screen in this case, as "stderr"? – Jeff Schaller Dec 17 '18 at 18:34
  • @JeffSchaller, I'm sorry. stderr – goodguy5 Dec 17 '18 at 18:57
  • 4
    Sorry, but you're having it completely backwards; you should redirect the output to a temporary file, and rename the temp file to the final destination if your command succeeds. t=$(mktemp); trap 'rm -f "$t"' EXIT INT TERM; the_cmd >"$t" && mv "$t" the_file. That way, the output file will always contain valid data irrespective on whether the command succeeded or failed. – mosvy Dec 18 '18 at 0:53
11

You must have "noclobber" set, check the following example:

$ echo 1 > 1  # create file
$ cat 1
1
$ echo 2 > 1  # overwrite file
$ cat 1
2
$ set -o noclobber
$ echo 3 > 1  # file is now protected from accidental overwrite
bash: 1: cannot overwrite existing file
$ cat 1
2
$ echo 3 >| 1  # temporary allow overwrite
$ cat 1
3
$ echo 4 > 1
bash: 1: cannot overwrite existing file
$ cat 1
3
$ set +o noclobber
$ echo 4 > 1
$ cat 1
4

"noclobber" is only for overwrite, you can still append though:

$ echo 4 > 1
bash: 1: cannot overwrite existing file
$ echo 4 >> 1

To check if you have that flag set you can type echo $- and see if you have C flag set (or set -o |grep clobber).

Q: How can I avoid writing a blank file when my base command fails?

Any requirements? You could just simply store the output in a variable and then check if it is empty. Check the following example (note that the way you check the variable needs fine adjusting to your needs, in the example I didn't quote it or use anything like ${cmd_output+x} which checks if variable is set, to avoid writing a file containing whitespaces only.

$ cmd_output=$(echo)
$ test $cmd_output && echo yes || echo no
no
$ cmd_output=$(echo -e '\n\n\n')
$ test $cmd_output && echo yes || echo no
no
$ cmd_output=$(echo -e ' ')
$ test $cmd_output && echo yes || echo no
no
$ cmd_output=$(echo -e 'something')
$ test $cmd_output && echo yes || echo no
yes

$ cmd_output=$(myAPICommand.exe parameters)
$ test $cmd_output && echo "$cmd_output" > myFile.txt

Example without using a single variable holding the whole output:

log() { while read data; do echo "$data" >> myFile.txt; done; }
myAPICommand.exe parameters |log
  • 1
    I like this answer and will likely accept it eventually. While it fixes my problem, it doesn't actually answer the question. – goodguy5 Dec 17 '18 at 14:59
  • I have updated my answer if that helps. – Evolter Dec 17 '18 at 15:52
  • lovely. Thank you. I didn't think of shortcircuit logic. – goodguy5 Dec 17 '18 at 16:10
  • 2
    I think you need to quote $cmd_output otherwise you get unexpected results if $cmd_output is (say) 1 == 2. If you want to protect against "$cmd_output" being only whitespace, I would consider piping it into grep -q with a suitable pattern. – Ben Millwood Dec 17 '18 at 16:35
  • I agree that it isn't bulletproof example @BenMillwood it just suppose to give an idea. With more requirements (different shells handle variables a bit differently, etc.) we could make it better :) – Evolter Dec 17 '18 at 16:50
11

You can delete the file after running, if the command fails, with

myAPICommand parameters > myFile.txt || rm myFile.txt

But I would suggest clobbering the file instead:

myAPICommand parameters >| myFile.txt

See What are the shell's control and redirection operators? for details.

3

You could create a script to run the myAPICommand.exe, but have it first remove the myFile.txt if it exists. Then you don't have to constantly do the rm command to clean up.

Like:

if [ -e myFile.txt ]
then
    rm myFile.txt && myAPICommand.exe
else

You could also make it so that your command cleans up after itself. If the file is empty adding something like the following.

Like:

if [ -s myFile.txt ]
then
        EXIT 0
else
        rm myFile.txt && EXIT 1
fi
  • 1
    Or just rm -f it, which won't complain if the file doesn't exist. – Ben Millwood Dec 17 '18 at 16:36
  • True.. @BenMillwood – Michael Prokopec Dec 17 '18 at 16:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.