1

I am trying to write a simple bash script that displays the contents of files.

#!/bin/bash

echo 'Input the path of a file or directory...'
read File

if [ -e $File ] && [ -f $File ] && [ -r $File ]
    then
    echo 'Displaying the contents of the file '$File
    cat $File


elif [ -d $File ] && [ -r $File ]
then
echo 'Displaying the contents of the directory '$File       
    for FILE in `ls -R $File`
        do
               cd $File/$FILE
               echo 'Displaying the contents of the file '$FILE
               cat $FILE
        done

else 
echo 'Oops... Cannot read file or directory !'
fi

The user should input a file or directory path. If the user inputs a file the program displays it with cat. If the user inputs a directory it should display the content of all files including those in the subdirectories. That part of the program doesn't work very well. I would like to get a result that doens't display errors like 'No such file or directory' but only the content of files. Can you help me ? Thanks in advance.

1

3 Answers 3

6

ls -R is the wrong tool to find all files in all subdirectories. find is a much better choice:

echo "displaying all files under $File"
find "$File" -type f -printf "Displaying contents of %p\n" -exec cat {} \;
Sign up to request clarification or add additional context in comments.

5 Comments

Thanks for your response ! The code works fine, but is there a way to print the name of the file just before displaying its content ?
… -exec echo {}; cat {} \;
Thanks chepner, but I get '' find: missing argument to `-exec' ''.
... -exec echo "Filename: {}" \; -exec cat {} \; --- edited answer
Don't use -exec echo ... it's silly. Use -printf "Displaying contents of %p\n" (or %f) instead.
3

You can print all files in the current directory just doing

for f in * do
    cat $f;
done

3 Comments

Yes but in the for loop he can add other commands (like the "debug" echo he has) easily. I just gave him the structure. Why wrong?
You are correct the loop allows more flexibility. The main issue is a for loop is the wrong approach. The OP uses ls -R which clearly means subdirectories are expected. Neither his loop nor yours handle this case properly. findis the way to go.
You can do recursive with shopt -s nullglob globstar; for subdir in **/*/ but then it gets tedious to separate out file and directories. find is certainly easier if you just want to cat files.
2

the find command will save you a lot of the logic:

#!/bin/bash 

echo 'Input the path of a file or directory...'
read File
DirName="."

if  echo $File | grep '/' ;  then
  DirName=$(dirname $File)
  File=$(basename $File)
fi

find "$DirName" -type f -name "$File" -exec cat {} \;
find "$DirName" -type d -name "$File" -exec ls {} 

The first find will look for all 'regular' (-type f) files name $File and cat them The second find will look for all 'directories' (-type d) and list them.

If they do not find any then the -exec portion will not execute. The grep will split the path is there is a slash in there.

2 Comments

Thanks for your response ! When I try to run your script I get an error ''find: warning: Unix filenames usually don't contain slashes...''.
to get around that you can split the name using basename and dirname e.g. find $(dirname $File) -name "$(basename $File)"

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.