How to tell "cat" command to not hang on when there is no path provided?

25,551

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

Share:
25,551

Related videos on Youtube

user72685
Author by

user72685

Updated on September 18, 2022

Comments

  • user72685
    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
      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
      Bratchley about 10 years
      Just 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
      Matteo Italia about 10 years
      Tip: 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
      smci about 10 years
      Default $1 to /dev/null if it does not exist.
  • mikeserv
    mikeserv about 10 years
    Above and beyond is generally best.
  • Chad K
    Chad K about 10 years
    @mikeserv who? where?
  • polym
    polym about 10 years
    this is the better solution in my opinion, since it exits with error
  • mikeserv
    mikeserv about 10 years
    @Creek - you, here.
  • user72685
    user72685 about 10 years
    There 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
    Chad K about 10 years
    @user72685 different strokes for different folks
  • Chad K
    Chad K about 10 years
    @mikeserv I have no idea what you're talking about ;)
  • mikeserv
    mikeserv about 10 years
    @Creek - have no fear, we're both floating that boat.
  • Keith Thompson
    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
    Vality about 10 years
    The 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
    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
    Cascabel about 10 years
    Not cat "$@"?
  • Matteo Italia
    Matteo Italia about 10 years
    Honestly, 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 than cp filename /dev/stdout.
  • Vality
    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
    heinrich5991 about 10 years
    @Vality Why should cp be faster if both aren't builtin?
  • Vality
    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 준영
    Léo Léopold Hertz 준영 over 7 years
    How can you throw a warning here if no such a file exists?
  • Warbo
    Warbo almost 7 years
    I 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 use 1>&2 rather than 1> /dev/stderr since there's no write permission for /dev/stderr.
  • Warbo
    Warbo almost 7 years
    I like the idea of 'using things properly', but I think cat may actually be better than cp in that regard. From a "capabilities" point of view, cp requires file read access, file write access and file creation access; if we do cat < "$1" > /dev/stdout or cat < "$1" instead, then cat 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 :)