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
1 Answer 1
Issues in this script:
- You are parsing the output of
ls
. Don't parsels
. - You are relying on filenames not to contain spaces or newlines. They can contain either.
- You're using
csh
. All by itself, that's a bad idea for shell scripts. Bash, Ksh, Zsh, almost anything butcsh
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:
-
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– Wildcard2016年11月18日 22:51:12 +00:00Commented 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.G-Man Says 'Reinstate Monica'– G-Man Says 'Reinstate Monica'2016年11月18日 23:51:30 +00:00Commented 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– Wildcard2016年11月18日 23:58:40 +00:00Commented 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– Wildcard2016年11月19日 00:01:38 +00:00Commented Nov 19, 2016 at 0:01 -
1Sorry; 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
.G-Man Says 'Reinstate Monica'– G-Man Says 'Reinstate Monica'2016年11月19日 00:24:34 +00:00Commented Nov 19, 2016 at 0:24
csh
. In my defense I was never a fan ofcsh
and I haven't used it in the last 20 years...bash
, it'scsh
. Inbash
theif
construct isif
condition; then
then-partelse
else-partfi
. Incsh
it is like you wrote,if (
condition) then
then-partelse
else-partendif
. Inbash
assignment is plain variable=
value --set
is fromcsh
.csh
you should add the proper shebang to the top of your script#!/bin/csh