How to tell "cat" command to not hang on when there is no path provided?
Solution 1
Your command also has another problem, what if the filename has spaces?
#!/bin/bash
cat "$1"
Always quote unless you have a compelling reason not to. And cat ""
does not hang. Instead it would produce an error message like "No such file or directory".
Solution 2
#!/bin/bash
if [[ "$#" -ne 1 ]]; then
echo "Usage: $0 [INPUT FILE]" 1>&2
exit 1
fi
cat "$1"
Solution 3
cat
will ignore STDIN
if you supply it with a filename. Connecting STDIN
to /dev/null
would be a valid solution in this context.
$ cat test.sh
#!/bin/bash
cat $1 < /dev/null
$ ./test.sh test.sh
#!/bin/bash
cat $1 < /dev/null
$ ./test.sh
$
The shortcoming of this approach is that it will return 0
if no file name is supplied. No way around that. Failure to open the specified file will still return failure.
Solution 4
I would say that cat is an unsuitable tool here and this is why you are getting this undesired behaviour, cat is designed to concatenate a set of files and write the output to another file, it is a quirk of the implementation that the default input is stdin and the default output is stdout.
I would say a far more suitable command here would be:
#!/bin/bash
cp ${1} /dev/stdout
The dev stdout directory is originally Linux only, however before I am yelled at for using a platform specific construct bash (the shell the op explicitly stated they are using) implements /dev/stdout as a builtin so is therefore usable on any platform with bash or ksh.
cp is a utility more suitable here as it is designed to copy the contents from one file to another and that is exactly what we are doing here, copying $1 to stdout
This command will also usefully fail given no input and works on any system with bash, note it does assume that the user has properly escaped any file names with odd chars like space or \n.
Solution 5
To display file contents only if the file exists:
#!/bin/bash
[ -f "$1" ] && cat "$1"
This script assumes that the first argument is the file you want to cat
Related videos on Youtube
user72685
Updated on September 18, 2022Comments
-
user72685 almost 2 years
I am simply trying to get a bash script
to return the content of a text file.#!/bin/bash cat $1
the problem is.. when the path to a file is not fed to this bash script... how will it even close itself.
because via regular command line... if there is no file path being fed to the cat command.. it does not hang up.
almost as if it is waiting for something..
-
Bratchley about 10 years
cat
is waiting for input from stdin which is how it's designed. If this is a concern for you, then you should be validating your inputs (which you should be doing anyways) by doing a-z
test or something. -
Bratchley about 10 yearsJust noticed @Creek posted this answer below. That's what you need to do. The
cat
command is doing what it needs to do. -
Matteo Italia about 10 yearsTip: always do
set -u
at the start of each script, at least you'll have an indication that there's a problem in the script arguments instead of calling potentially destructive commands with the wrong parameters. -
smci about 10 yearsDefault
$1
to/dev/null
if it does not exist.
-
-
mikeserv about 10 yearsAbove and beyond is generally best.
-
Chad K about 10 years@mikeserv who? where?
-
polym about 10 yearsthis is the better solution in my opinion, since it exits with error
-
mikeserv about 10 years@Creek - you, here.
-
user72685 about 10 yearsThere are lots of votes for this answer but perhaps because this is an english only web site .. people from other parts of the world are not really voting.. it is not balanced. simplicity saves the day with the chosen answer.
-
Chad K about 10 years@user72685 different strokes for different folks
-
Chad K about 10 years@mikeserv I have no idea what you're talking about ;)
-
mikeserv about 10 years@Creek - have no fear, we're both floating that boat.
-
Keith Thompson about 10 years
cat ""
doesn't hang, but it does print an error message:cat: : No such file or directory
(referring to the empty string). It's better to test whether$1
exists, probably by checking the value of$#
. -
Vality about 10 yearsThe main problem I see here is that if one is running a file system which allows an empty file name this could actually work and not error. However, as a quick hack this is fine.
-
frostschutz about 10 years@Darkhogg: If there is such a file the test would succeed also. I assume the OP's script is in reality more complicated and this was just an example regarding
cat
invocation. Other answers went more to the error handling route. Someone even deleted his answer; oh well. something for everyone here. -
Cascabel about 10 yearsNot
cat "$@"
? -
Matteo Italia about 10 yearsHonestly, this seems to me like an overcomplication;
cat
was born to concatenate files, but everybody uses it just to show files contents probably since the first version of UNIX, and I see nothing wrong with that -cat "filename"
is way shorter, more portable and more idiomatic thancp filename /dev/stdout
. -
Vality about 10 years@MatteoItalia I give you that it is shorter, and potentially more idiomatic but it is not significantly more portable, every shell I have seen in over a decade (with the possible exception of csh) had implemented the cp version, I will note that there is a performance impact if your chosen shell makes one a builtin and the other an external command. However if neither are builtin cp will be faster. Regarding the expressiveness I suppose it depends what you are used to.
-
heinrich5991 about 10 years@Vality Why should
cp
be faster if both aren't builtin? -
Vality about 10 years@heinrich5991 I have benchmarked this for a 512MB text file in a variety of machines, on average with these machines cat takes 1.79 seconds and cp takes 1.42 seconds. It seems from running a performance analyzer that cat is copying in small chunks and running a loop for every char printed, cp just splices the files together at high speed.
-
Léo Léopold Hertz 준영 over 7 yearsHow can you throw a warning here if no such a file exists?
-
Warbo almost 7 yearsI came across this and just thought I'd mention that even in bash, on Linux, a script might not have write permission for files/descriptors like
/dev/stdout
. I've encountered this in Nix build scripts, for example having to use1>&2
rather than1> /dev/stderr
since there's no write permission for/dev/stderr
. -
Warbo almost 7 yearsI like the idea of 'using things properly', but I think
cat
may actually be better thancp
in that regard. From a "capabilities" point of view,cp
requires file read access, file write access and file creation access; if we docat < "$1" > /dev/stdout
orcat < "$1"
instead, thencat
only needs read/write access to its own stdio channels. In situations where we're delegating to more complex tools, or where we have more fine-grained permissions, this can be useful to keep in mind :)