2

First, I am newer than new, I'm sorry this is so long, but the forum rules ask for details.

Also sorry this is printing out weird.

Here is what I am trying to do: I am stuck on part (B)

The script you create must use only relative paths for all paths in the code. You must assume that the script is being run from the ~ directory.

(A) Create a shell script that loops through all items in a directory given by the user using the "read" builtin. The script must validate the input and use a loop to only allow the script to proceed after the validation is complete. It must validate that the directory given is a directory.

(B) The script, while iterating over the items in the directory, should test the items to see if they are directories or files.

  • (B.1) If they are directories then the script needs to loop over the directory and count the number of items inside of the directory (not recursively). The script needs to output both the name of the directory and the number of files (and folders) inside of it to the same line of a file named "~/sorter/directory_listing.txt".

  • (B.2) If they are files they need to be examined for size using du with human readable output. Your script will have to write the size followed by a space then the file name to a new line of the file "~/sorter/files_and_sizes.txt".

(C) After the loop finishes the files_and_sizes.txt file needs to be sorted human readable then output to a file ~/sorter/files_sorted.txt The directory_listing.txt file needs to be sorted reverse by the number of items in the directory and output to a file named ~/sorter/dir_reverse.txt

My attempt:

read -p "Please enter a directory " chosen_dir

while [[ ! -d "$chosen_dir" ]]
do
 echo Please enter a valid directory && read chosen_dir
done

for i in $chosen_dir/*;

    do
        counter=$((counter+1))
        if [ -d "$chosen_dir" ]; then
            ls "$chosen_dir" | wc -l > sorter/directory_listing.txt
        else
            if [ -f "$chosen_dir" ]; then
                du -sh "$chosen_dir"/* > sorter/files_and_sizes.txt
        fi
    done

RESULT:

blahblah@vm1:~$ ./taratest.sh
Please enter a directory testsort
./taratest.sh: line 26: syntax error near unexpected token `done'
./taratest.sh: line 26: `    done'

When I remove the done I get this ….

NEW RESULT:

blahblah@vm1:~$ ./taratest.sh
Please enter a directory testsort
./taratest.sh: line 27: syntax error: unexpected end of file

THEN: I searched on here for while iterating over the directory, test to see if the items are files or directories in bash

and changed to THIS:

first part of script, then…

for i in "$chosen_dir"/*

do
    [ -f "$chosen_dir" ] && echo "is File"

    [ -d "$chosen_dir" ] && echo "is Directory"


done

I KNOW THE OUTPUT IS NOT WHAT'S IN THE DIRECTIONS, I AM ECHOING JUST FOR TEST PURPOSES

RESULTS:

Please enter a directory testsort

is Directory

is Directory

is Directory

is Directory

2 are files & 2 are dirs., so why is it saying 4 dirs

blahblah@vm1:~$ ls -lh testsort
total 8.0K
drwxrwxrwx 2 blahblah student 68 Jun  4 17:41 dir1
drwxrwxrwx 2 blahblah student 68 Jun  4 17:41 dir2
-rwxrwxrwx 1 blahblah student  0 Jun  4 17:41 file1.txt
-rwxrwxrwx 1 blahblah student  0 Jun  4 17:41 file2.txt

Any guidance on solutions is greatly appreciated.

  • 3
    for i in "$chosen_dir"/* so your loop variable is $i i.e. you should be doing [ -f "$i" ] and so on. As it stands, you are repeatedly testing the parent directory "$chosen_dir" instead. – steeldriver Jun 6 '16 at 0:18
1

The problem is that you have this construct:

for [stuff]; do
   if [test]; then
       [stuff]
   else
       if [test]; then
          stuff
   fi
done

You have two nested ifs, which is fine, but you only terminate one of them with fi. You need to do one of these:

# Alternative one:
for [stuff]; do
   if [test]; then
       [stuff]
   else
       if [test]; then
          stuff
       fi
   fi
done

# Alternative two
for [stuff]; do
   if [test]; then
       [stuff]
   elif [test]; then
       stuff
   fi
done
1

Another problem with this is that you (correctly) quote the variable when you test it with -d, but fail to quote it in the for loop.

Instead of:

for i in $chosen_dir/*;

    do

Use:

for f in "$chosen_dir"/*; do

(The name change and whitespace change are style points; the added double quotes are important.)


I don't know what you're trying to use the counter for, because you never actually used it. Nor did you reference $i ($f in my version) which based on the for construct given above will contain the name of each file (or subdirectory) in "$chosen_dir", in turn.

By the way, thanks for specifying that this is homework. There could be much shorter solutions, but your general approach is fine if you fix the syntax errors and also quote your variables.


For the count of files within a subdirectory, you may not get an accurate count with the command you're using. (Actually you'll never get an accurate count with the command: ls "$chosen_dir" | wc -l because you're not testing the subdirectory, you're testing the directory entered by the user.) Rather than just ls, you might consider using ls -1 -A "$i" so that the line count will give an accurate count of the files within the subdirectory. (See man ls for details on the -1 and -A flags.)

This still won't correctly handle filenames that contain newlines, but for homework I highly highly highly doubt you will get any points off for that. (Many scripts actually used in production also fail on filenames which contain newlines; such names pretty much only come from malicious users.)


I assume you can work out part C yourself. ;) (See man sort if you need to, and search the sort tag on this site also.)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.