4

With cat, I am able to hide the "No such file or directory" error like so:

cat file.txt 2>/dev/null

However, this shows the error

< file.txt 2>/dev/null
bash: file.txt: No such file or directory

How can I print the file contents if the file is found, but hide errors if it is not?

Note: I am making the intentional effort to avoid the use of the cat command: https://stackoverflow.com/questions/11710552/useless-use-of-cat

TuxForLife
  • 2,909

5 Answers5

4

Just change the order and do the redirection of stderr to /dev/null FIRST:

%% <file.txt 2>/dev/null
bash: file.txt: No such file or directory
%% 2>/dev/null <file.txt
%%

Keep in mind that redirections are always performed from left to right; the idea is to have the stderr already redicted when the failing redirection is performed.


However, AFAIK, only zsh allows you to use just <file as an equivalent of cat file (or more file, subject to its NULLCMD and READNULLCMD options).

While bash and some other shells deceptively support $(<file) as a special form of command substitution, they only support that exact form, nothing more:

bash% echo text > file
bash% <file
bash% echo $(<file)
text
bash% echo $(<file;<file)

bash%

While in zsh:

zsh$ <file
text
zsh$ <file >out
zsh$ <out
text
zsh$ echo $(<file;<file)
text text
  • Unfortunately, echo $(2>/dev/null <file) returns nothing even when the file is found with contents – TuxForLife Feb 21 '20 at 21:03
  • 1
    And that's just what I was saying: only the exact $(<file) form of command substitution is supported in bash. What is your objection? That particular example of yours could be rewritten as { echo "$(<file)"; } 2>/dev/null, but I don't see the point of it. –  Feb 22 '20 at 01:28
3

Your first example will do what you want.

Your second example won't do anything useful because you haven't got a command. If you are trying to represent the redirection of stdin in a command such as cat <file so that the error generated when file doesn't exist is hidden, you have a few choices; here are three

[ -f file ] && cat <file           # subject to race condition

( exec 2>/dev/null; cat <file )    # subshell discards all error output

( cat <file ) 2>/dev/null          # subshell discards all error output

If you're using bash you can replace ( ... ) with { ...; } and [ ... ] with [[ ... ]].

Chris Davies
  • 116,213
  • 16
  • 160
  • 287
1

You could use a find with cat.

find . -name file.txt -exec cat {} \;

If there will return the contents of the file and if not found just returns to prompt. Either run from where you are looking or change the . to a path like /tmp or something

find /tmp/ -name file.txt -exec cat {} \;
  • This doesn't check if the file is readable or not, only that it exists. But even you do (try to) check if it is indeed readable, that leaves open the chance of someone changing the permissions just between the check and the launching of cat, so you might still get errors. – ilkkachu Feb 20 '20 at 21:53
1

How can I print the file contents if the file is found, but hide errors if it is not?

Test if the file exists first?

if [ -f "$file" ]; then
    cat "$file"     # or whatever it is you're running
fi

or if it's readable

if [ -r "$file" ]; then ...

Both of those suffer from a TOCTTOU (time-of-check to time-of-use) vulnerability, in that the file could be removed or its permissions changed just after the test, before cat runs. That would probably give you an error anyway. Similarly, some odd device file or such might appear to be readable, but still give an error when read.


If there's a pipeline you're running, you might as well put the cat there to read the file. That way, the timing issue would not exist:

cat "$file" 2>/dev/null | whatever...

I know you didn't ask for this, but the cat is not useless here. It's being used to separate the errors from reading $file from whatever other errors the right-hand side of the pipeline might produce.

ilkkachu
  • 138,973
0

Try this,

find . -maxdepth 1 -name file.txt -type f -readable -exec cat {} \;
  • -maxdepth 1 check only in the current directory
  • -name Base of the filename matches the pattern.
  • -type -f type of the file as a regular file
  • -readable Matches files which are readable
  • exec cat execute the command cat which the conditions above are satisfied.

So we won't get an error for the absence of file and unreadable.

NOTE: All files are readable for root.

Siva
  • 9,077