8

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?

5
  • 1
    How is failure indicated? A return code? An empty file? Commented Dec 17, 2018 at 14:52
  • @JeffSchaller error is written to the command line, in this case. Commented Dec 17, 2018 at 18:33
  • "command-line" meaning redirected to myFile.txt as "stdout", or to the screen in this case, as "stderr"? Commented Dec 17, 2018 at 18:34
  • @JeffSchaller, I'm sorry. stderr Commented Dec 17, 2018 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. Commented Dec 18, 2018 at 0:53

3 Answers 3

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
7
  • 1
    I like this answer and will likely accept it eventually. While it fixes my problem, it doesn't actually answer the question. Commented Dec 17, 2018 at 14:59
  • I have updated my answer if that helps. Commented Dec 17, 2018 at 15:52
  • lovely. Thank you. I didn't think of shortcircuit logic. Commented Dec 17, 2018 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. Commented Dec 17, 2018 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 :) Commented Dec 17, 2018 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
2
  • 1
    Or just rm -f it, which won't complain if the file doesn't exist. Commented Dec 17, 2018 at 16:36
  • True.. @BenMillwood Commented Dec 17, 2018 at 16:37

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.