1

I'm writing a shell script that is supposed to take in one parameter (a directory name) and display how many files, directories, readable files, writable files and executable files are in that directory. If a parameter isn't given when you run it, its supposed to display an error message and abort. If the given parameter doesn't exist it should also display an error message and abort. Otherwise it should display the above info. I cannot for the life of me get it to run. Here is what I have, please help!:

   #!/bin/csh
   $1
   set file=$1
       if ($file==0)then
             echo "usage: assignment6.sh <directory_name>"
             exit0
       else
           if (-e $file && -r $file) then
                echo "Number of Directories: `ls | wc -w`"
                echo "Number of Files: `ls -d */ | wc -w`"
                echo "Number of Readable files: `find * -type f -or -type d -maxdepth 0 -perm +u=r | wc -w`"
                echo "Number of Writable files: `find * -type f -or -type d -maxdepth 0 -perm +u=w | wc -w`"
                echo "Number of Executable files: `find * -type f -or -type d -maxdepth 0 -perm +u=x | wc -w`"

            else
                if (! -e $file) echo "No such directory."
                exit 0
            endif
       endif
 exit 0
11
  • In what language is that script written?
    – AlexP
    Commented Nov 18, 2016 at 21:42
  • yeah it's bash.
    – Maddie
    Commented Nov 18, 2016 at 21:50
  • Sorry, mind block. It's csh. In my defense I was never a fan of csh and I haven't used it in the last 20 years...
    – AlexP
    Commented Nov 18, 2016 at 21:50
  • 1
    No it's not bash, it's csh. In bash the if construct is if condition ; then then-part else else-part fi. In csh it is like you wrote, if (condition) then then-part else else-part endif. In bash assignment is plain variable=value -- set is from csh.
    – AlexP
    Commented Nov 18, 2016 at 21:52
  • @Maddie, if this is csh you should add the proper shebang to the top of your script #!/bin/csh Commented Nov 18, 2016 at 21:54

1 Answer 1

2

Issues in this script:

  1. You are parsing the output of ls. Don't parse ls.
  2. You are relying on filenames not to contain spaces or newlines. They can contain either.
  3. You're using csh. All by itself, that's a bad idea for shell scripts. Bash, Ksh, Zsh, almost anything but csh is a better idea. (My opinion, but read through the linked factual reasoning.)

Here is a POSIX compliant version of part of this program. (If I have time later I may include the rest of the features.)

This won't handle cases where there are more files than fit in an argument list, but it could be modified to do so if really necessary.

#!/bin/sh

[ "$#" -eq 1 ] && [ -d "$1" ] || {
  printf 'Usage:\t%s <directory>\n' "$0"
  exit 1
}

dirs="$(find "$1" -path '*/*/*' -prune -o -type d -exec sh -c 'printf %s\\n "$#"' sh {} +)"
files="$(find "$1" -path '*/*/*' -prune -o -type f -exec sh -c 'printf %s\\n "$#"' sh {} +)"

printf 'Number of directories in %s:\t%s\n' "$1" "$dirs"
printf 'Number of files in %s:\t%s\n' "$1" "$files"

Since the -maxdepth primary is not portable, I made use of the techniques described here:

5
  • Actually this will report one directory too many, as it reports itself. Unfortunately I don't have time to work on it further at this moment.
    – Wildcard
    Commented Nov 18, 2016 at 22:51
  • Also, unless I'm misunderstanding, it will fail if there are so many files / directories, or their names are so long, that they cannot be passed on a single command line. But +1 for everything else. Commented Nov 18, 2016 at 23:51
  • @G-Man, correct; I mentioned that actually. Feel free to make an edit if you think that wasn't made clear enough.
    – Wildcard
    Commented Nov 18, 2016 at 23:58
  • @G-Man, I haven't made the necessary huge number of files to test, but I believe all that would be necessary to handle vast numbers of files would be dirs="$(printf %s "$dirs" | tr '\n' + | bc)". Right?
    – Wildcard
    Commented Nov 19, 2016 at 0:01
  • 1
    Sorry; it's clear enough.  I read it too quickly and skidded over that paragraph. … … … I can't get your answer to work; I believe that you need (printf "%s" "$dirs" | tr '\n' +; echo) | bc.  Or (much as I hate to use unquoted variables), echo $dirs | tr " " + | bc. Commented Nov 19, 2016 at 0:24

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .