I have a simple syntactically wrong command like this that is meant to be run on Unix/Linux hosts

$ echo "first string $PATH" > out.lst
$ ECHO second string %PATH% > out.lst

The first line will succeed and fill the out file, whilst the second will fail emptying the previously filled file.

I'm trying to find a way to preserve the content of the file in case an error occurs in calling some command whose output is meant to override the file.

The use case is a bit strange: I'm trying to write a portable SQL script for Oracle SQL*Plus that is meant to call commands from the underlying OS that may be either Linux or Windows. Being not possible to detect the OS, I'm calling both the commands for the two platform and trying to make the things work just by not raising the exception.

On windows, both lines will succeed and the second will override the first. On Linux, the second line will fail, but I want to preserve the content of the file.

  • See also unix.stackexchange.com/q/452865/117549 – Jeff Schaller Jan 23 '20 at 10:31
  • How is it not possible to detect the OS? Just run a pair of similar junk commands on junk files at the top of your script, and remember which worked and which failed. Then use that information for all following cases. – Paul_Pedant Jan 23 '20 at 12:06

Using >, the file will always be emptied before the actual redirect takes place. You can use >> to append subsequent redirects to the same destination.

  • So one approach to use is to redirect each command's standard output to a nonce temporary file, and then mv the temporary to the final filename if the exit status of the command is success. (Remember to clean up/re-use the temporary on failure.) This is a widespread pattern in makefiles. – JdeBP Jan 23 '20 at 10:56

There are a lot of tricks to make scripts working on both windows and unix, see for example this question on stackoverflow.

Example: put a : at the beginning of the unix command so that cmd.exe skip it, and a # at its end so that the unix shell don't choke on the extra carriage-return:

:; echo "unix path = $PATH" > out.lst; exit #
@echo off
echo windows path = %PATH% > out.lst

If you need multiple lines, you should combine a here-document on the unix side with a goto label .. : label on the windows side:

:; true <<EOT
@echo off
echo windows path = %PATH% > file.txt
echo windows sux
goto skip
echo "linux path = $PATH" > file.txt #
echo linux sux #
: skip

Notice that the <<EOT should be the last on the line, and all lines in the unix part should end with a # in order to not append a spurious ^M to the end of the lines or the filenames.

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.