0

I have a folder with this content (the subfolders and file names are fixed and cannot change):

# ls
data/ config/ myfile

I need to create a tar archive to stdout to process it with dd in a Bash script; suppose for example in this way for the sake of simplicity:

# /bin/tar -cz data config myfile 2>/dev/null | /bin/dd of=backup.tar 2>/dev/null

Immediately after this instruction I check the variable ${PIPESTATUS[0]} for 0 to know that tar did its work successfully.

The problem is that myfile is optional for me, and if it's missing my ${PIPESTATUS[0]} becomes 2 even though I don't want to consider it an error. So how can I instruct tar to ignore missing input files? I would prefer a one-line statement, if possible.

0

If it is an option to change the tar call:

test -e myfile && myfile=myfile || myfile=
/bin/tar -cz data config $myfile 2>/dev/null |
0

So how can I instruct tar to ignore missing input files?

It's really simple: just use the --ignore-failed-read flag on your tar command:

$/bin/tar -cz --ignore-failed-read data config myfile 2>/dev/null | /bin/dd of=backup.tar 2>/dev/null

$ echo ${PIPESTATUS[0]}

> 0

BTW: Note that the answer of Hauke Laging is more cumbersome, but tar only returns 0 if it's all ok, or if the only file missing is myfile... with this, tar returns 0 if it's all ok, or even when any file is missing.


With this:

/bin/tar -cz --ignore-failed-read data config myfile | /bin/dd of=backup.tar 2>/dev/null

(note that I'm not redirecting stderr of tar to /dev/null) if myfile doesn't exist, tar returns 0 (if there is no other errors, of course) and you get this on stderr: /bin/tar: myfile: Warning: Cannot stat: No such file or directory

tar manual says:

‘--ignore-failed-read’ Do not exit with nonzero on unreadable files or directories. This option has effect only during creation. It instructs tar to treat as mild conditions any missing or unreadable files (directories). Such failures don’t affect the program exit code, and the corresponding diagnostic messages are marked as warnings, not errors. These warnings can be suppressed using the ‘--warning=failed-read’ option

but, alas, --warning=failed-read suppress all warnings about read-errors: in your case, suppress warnings about a file that doesn't exist, but also suppress warning about I/O errors, for example... is far from optimal; apparently, tar doesn't have a flag to say it: hey, suppress failed-read warning only if the file doesn't exist, so, may be, this resolve your problem:

/bin/tar -cz --ignore-failed-read data config myfile 2> >(grep -v 'No such file or directory' 1>&2) | /bin/dd of=backup.tar 2>/dev/null

this: >( ... ) is Process Substitution

this way, your tail command doesn't change its return number if the file doesn't exist, you don't get warning messages about missing files, and you get warning messages about any other read error.


this>

I can't help thinking that none of this solutions are really good, so, I came up with this:

/bin/tar -cz -T <(\ls -A -1) 2>/dev/null | /bin/dd of=backup.tar 2>/dev/null

with this, your are sending to tar only the files that really exists at the time of command execution: you don't need to worry about their names, or even which file exists or not: you always execute the same command (no matter what), scales perfectly if you have 1 file missing, or n files missing, and you don't miss any errors.

(note the backslash if front of ls command: this way, you prevent any ls alias, thus, its output is more reliable)

  • But what happens if there are really some errors during the read operation in the data or config folders? I would like to ignore not-found errors but not actual I/O errors. – virtualdj May 13 '18 at 9:23
  • Check my updated answer – matsib.dev May 13 '18 at 12:24
  • Thanks, I tried with --ignore-failed-read but if there are some files inside config/ for example that the current user doesn't have permission to read this command returns 0: # tar cz --ignore-failed-read data config myfile | /bin/dd of=backup.tar tar: config/config.txt: Warning: Cannot open: Permission denied 0+1 records in 0+1 records out # echo ${PIPESTATUS[0]} 0 and this is wrong for me! The process substitution is a bit too much complex too, so I think I'll stick with Hauke's solution. – virtualdj May 14 '18 at 18:37
  • I think that none of the previous solutions are good enough: check my last update – matsib.dev May 15 '18 at 1:46

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.