beginner bash writing

LordTrell

New Member
Credits
0
Hello! i am new to bash, need assistance with a script for some assignment:...

A shell script to list out the contents of any directory, and indicate for each file (including invisible ones) whether the file is a directory, a plain file, and permissions such as executable ect

i can list out the directories but not sure how to add all the permissions
for dirs in "$checkdir"/*
do
echo "$dirs"
done
 


atanere

Well-Known Member
Credits
0
Hi @LordTrell, and welcome! I'm much better at asking code questions than giving solutions, but we do have some folks on here that I'm sure will be able to help you better. But until then, let me try to focus on your assignment better...

You say, "list the contents of any directory"... but your code example has hard-coded into it to output just the contents of the "/" (root) directory. How do you want to get "any" directory? Do you need the user of your script to provide you input to tell you which directory? Or do you just want to copy the script to each directory that you want to check?

Are you yet familiar with the ls command? If you open an terminal and use ls by itself, it will show you all the directories and files inside the directory you are in, similar to the code you have written above. If you add a couple of options, like ls -al, it will show you much more. In fact, that simple command will show you everything that you have asked for: hidden files/folders (that start with a "."), permissions (in the form of rwxrwxrwx... "read, write, execute"), and whether each item is a file or a directory (the first character for each item, preceeding the permissions, is the key: a "d" for directory, or a "-" for a file... but be careful as that character can identify other things also, such as links, and more). From what you've said, if you can work this command into your script, it may give you everything required by your assignment.

To help make your code more readable on forums such as ours, it helps a lot if you will enclose your code inside of code "tags"... between tags like this: [code] [/code]. See the difference below:

Code:
#!/usr/bin/env bash

for dirs in "$checkdir"/*
do
echo "$dirs"
done
Okay, that's all I've got. Good luck with your assignment, and I'm sure some others here will be able to help you more. But remember too that Google can often steer you to the knowledge you need... and researching/solving problems yourself will stick with you better. There is literally tons of info on the web about Linux terminal commands and shell scripting... jump in and learn all you can!

Cheers
 

JasKinasis

Well-Known Member
Credits
848
Technically, you don't need a script - you can do the whole thing with a single ls statement:
Code:
ls -AlhFR --color /path/to/directory_to_list
The flags do the following:
-A - lists ALMOST ALL files
That is :- ALL files except . and ..
IF you want to include . and .. in the output use the lowercase a flag instead.
-l - formats the output in a list format, including permissions information
-h - prints file-sizes in human readable formats
-F - classifies each object by appending characters to the end of the listing - e.g. executable files will have an asterisk * at the end, directories will have a forward slash / at the end, ordinary files will have nothing at the end etc.
-R - will recursively list subdirectories.
--color - will colourize the output, hopefully making it easier to distinguish between the different types of objects listed.

Wrapping that one line into a script would be fairly pointless, but would look something like this:
Code:
#!/usr/bin/env bash

if [[ $# -ne 1 ]] || [[ ! -d $1 ]]; then
    echo "ERROR: This script accepts a single parameter, which must be a path to a valid directory!"
    exit 1
fi

ls -AlhFR --color $1
The above script first ensures that it was passed a single parameter AND that the parameter is a valid path to a directory.
- If either of these conditions are not met, it outputs an error message and exits with 1 - which typically indicates that a program or script has failed.

If we get past the check, then we received a valid path to a directory, so we use our ls command to recursively list the directory with all of our required flags set.

So it depends on what your teacher/lecturer/professor has specified.
You might be able to get away with just providing the one-line solution, but if you really need to wrap it in a script - go for it!

[edit]
I didn't notice that stan had already replied to this thread. I logged in to answer the question before it had any replies, but then I had to answer the phone part way through writing my post. It was a long phone call! :/
[/edit]
 
Last edited:

LordTrell

New Member
Credits
0
Technically, you don't need a script - you can do the whole thing with a single ls statement:
Code:
ls -AlhFR --color /path/to/directory_to_list
The flags do the following:
-A - lists ALMOST ALL files
That is :- ALL files except . and ..
IF you want to include . and .. in the output use the lowercase a flag instead.
-l - formats the output in a list format, including permissions information
-h - prints file-sizes in human readable formats
-F - classifies each object by appending characters to the end of the listing - e.g. executable files will have an asterisk * at the end, directories will have a forward slash / at the end, ordinary files will have nothing at the end etc.
-R - will recursively list subdirectories.
--color - will colourize the output, hopefully making it easier to distinguish between the different types of objects listed.

Wrapping that one line into a script would be fairly pointless, but would look something like this:
Code:
#!/usr/bin/env bash

if [[ $# -ne 1 ]] || [[ ! -d $1 ]]; then
    echo "ERROR: This script accepts a single parameter, which must be a path to a valid directory!"
    exit 1
fi

ls -AlhFR --color $1
The above script first ensures that it was passed a single parameter AND that the parameter is a valid path to a directory.
- If either of these conditions are not met, it outputs an error message and exits with 1 - which typically indicates that a program or script has failed.

If we get past the check, then we received a valid path to a directory, so we use our ls command to recursively list the directory with all of our required flags set.

So it depends on what your teacher/lecturer/professor has specified.
You might be able to get away with just providing the one-line solution, but if you really need to wrap it in a script - go for it!

[edit]
I didn't notice that stan had already replied to this thread. I logged in to answer the question before it had any replies, but then I had to answer the phone part way through writing my post. It was a long phone call! :/
[/edit]

hello! thanks for the assistance. it has to be a script for sure.. i do havea script that print out all the file permissions of all files but not the contents in the directories - i need to combine themboth somehow


Code:
echo -n "Enter the file name    :"

read name

if test -f $stufftime

     then

             echo "Its is a file and it has "

             if test -r $stufftime

                    then

                          echo "Read permission "

                     fi

             if test -w $stufftime

                    then

                          echo "Write permission "

                     fi

              if test -x $name

                    then

                          echo "Execute permission "

                     fi

elif test -d $stufftime

     then

             echo "Its is a directory and it has "

             if test -r $stufftime

                    then

                          echo "Read permission "

                     fi

             if test -w $stufftime

                    then

                          echo "Write permission "

                     fi

              if test -x $stufftime

                    then

                          echo "Execute permission "

                     fi

else

       echo "Does not find any file or directory named $stufftime

fi


#that needs to be combined with this below

for dirs in "$checkdir"/*
do
echo "$dirs"
done
 

JasKinasis

Well-Known Member
Credits
848
I think before I go too far, we need to clearly define the problem that you have been set.

Imagine we have this structure in our file-system:
Code:
/path/to/directory/
     file1
     file2
     file3
     /subdirectory1/
          file4
     /subdirectory2/
          file5
          file6
So the files: file1, file2, file3 and sub-directories subdirectory1 and subdirectory2 are all in a directory at /path/to/directory/

If the user enters /path/to/directory/file1, your script should output that the target was a file and the permissions for file1 and that is that. I get that much.

But if the user enters a directory -
e.g. /path/to/directory/

- how far down the rabbit hole is your script supposed to go?

Should it just output the permissions for the main directory (/path/to/directory) and the permissions and types of it's contents:
e.g.
files 1,2,3 AND subdirectories 1 and 2?

Or does it also need to recurse into the subdirectories and list the content/permissions for files/directories they contain?

I just want to get a firm grasp of the problem you are trying to solve so I don't end up suggesting unnecessary things.

One thing that might help would be putting the permissions checking code into a function.
That way, whenever you want to check the permissions of a file or directory, you can simply call the function and pass it the file/directory to check.

So perhaps, you get the name of the file/directory to check. If it is a file, call your checkpermissions function on the file and end.

If the target is a directory output the permissions for the directory:
Code:
checkpermissions "$checkdir"
Then get each file-system object in the directory and pass it to the checkpermissions function:
Code:
for fsObj in "$checkdir"/*; do
      checkpermissions "$fsObj"
done
That would work with the top-level of things.
e.g. If you were only interested in the directory's immediate, top-level contents.

If full recursion is required, it would require a slightly different approach.

With the full-recursion, you'd do something like:
1. Get the name of the file/directory to check
2. Pass the object to the checkpermissions function

The checkpermissions function would deal with determining if the passed-in object is a file or a directory.
If it is a file - it outputs the permissions and returns.
If it is a directory, it uses something like my "for fsObj.." example to list the content of the directory and call checkpermissions on each object - so in other words - checkpermissions recursively calls itself each time it is passed a directory.

I hope that makes some sense!

[EDIT]
Also, what if a directory contains something that is NOT a file or a directory - like a symbolic link (which could point to a file or a directory)? Should your script ignore it? or report it?
[/EDIT]
 
Last edited:

JasKinasis

Well-Known Member
Credits
848
Here's something I've just quickly knocked up to illustrate the full-recursion idea:
notls.sh
Code:
#!/usr/bin/env bash

# Set up some functions:

# Quit with an error message
die()
{
   echo "ERROR - [email protected]"
   exit 1
}

# List permissions for a file-system object
listPermissions()
{
  echo -n "Permissions for $1: "
  if [[ -r "$1" ]]; then
     echo -n "Read, "
  fi
  if [[ -w "$1" ]]; then
     echo -n "Write, "
  fi
  if [[ -x "$1" ]]; then
     echo -n "Execute"
  fi
  echo;echo;

}

# Determine the type of object we are dealing with
checkType()
{
  if [[ -f "$1" ]]; then
     echo "$1 is a file"
      listPermissions "$1"
  elif [[ -d "$1" ]]; then
     echo "$1 is a directory"
     listPermissions "$1"
     for fsobj in $1/*; do
         checkType "$fsobj"
     done
  else
     echo "$1 is not a file or a directory!"
     listPermissions "$1"
  fi
}

# Main body of script:

# Ensure we have exactly one parameter
if [[ $# -ne 1 ]]; then
   die "takes one parameter - a path to a directory or a file"
fi

# Ensure the parameter is an existing file-system object
if [[ ! -e $1 ]]; then
   die "$1 does not exist!"
fi

# Find out what we're dealing with!
checkType "$1"
Rather than asking the user to enter a path to a file/directory, the above script takes the path to the file/directory as a parameter.
So the above script is ran like this:
Code:
./notls.sh /path/to/fileOrDirectory
NOTES:
The [[ and ]] operators in the script are equivalent to using "test".

All of the $1's that are peppered throughout the script might seem a bit confusing at first. But the thing to bear in mind is that in each of the functions - $1 always refers to the first parameter that was passed to the function.

Whereas in the main body of the script (the last few blocks of code in the file) - $1 always refers to the first parameter that was passed to the script!

Ignoring the functions for now, the main body of the script does the following:
1. Ensures that we have exactly one parameter
- If not, call the die function which displays an error message and exits with an error code.

2. Checks that the sole parameter to the script ($1) exists.
- If not, we call the die function and display an error message.

3. Call the checkType function, passing parameter1 ($1)

The checkType function is where the all the recursive magic happens.

If the parameter passed to checkType is a file, we output that it is a file and call the listPermissions function to list the permissions that it has.

If the parameter passed to checkType is a directory, we output that it is a directory and call listPermissions to display its permissions.
Then we list the objects in the directory and pass each one to checkType.
So we are calling checkType from inside checkType!
This is called recursion.

[edit]
It should be noted that the script in this post will NOT list hidden files.
Offhand, the easiest fix for that might be to use ls in our for loop.
But if we're going to be using ls in our script, then you may as well use my original script - which just wrapped a single call to ls! XD
Another way might be to use a regex in the for loop to get all hidden and non-hidden files.
[/edit]
 
Last edited:

LordTrell

New Member
Credits
0
I think before I go too far, we need to clearly define the problem that you have been set.

Imagine we have this structure in our file-system:
Code:
/path/to/directory/
     file1
     file2
     file3
     /subdirectory1/
          file4
     /subdirectory2/
          file5
          file6
So the files: file1, file2, file3 and sub-directories subdirectory1 and subdirectory2 are all in a directory at /path/to/directory/

If the user enters /path/to/directory/file1, your script should output that the target was a file and the permissions for file1 and that is that. I get that much.

But if the user enters a directory -
e.g. /path/to/directory/

- how far down the rabbit hole is your script supposed to go?

Should it just output the permissions for the main directory (/path/to/directory) and the permissions and types of it's contents:
e.g.
files 1,2,3 AND subdirectories 1 and 2?

Or does it also need to recurse into the subdirectories and list the content/permissions for files/directories they contain?

I just want to get a firm grasp of the problem you are trying to solve so I don't end up suggesting unnecessary things.

One thing that might help would be putting the permissions checking code into a function.
That way, whenever you want to check the permissions of a file or directory, you can simply call the function and pass it the file/directory to check.

So perhaps, you get the name of the file/directory to check. If it is a file, call your checkpermissions function on the file and end.

If the target is a directory output the permissions for the directory:
Code:
checkpermissions "$checkdir"
Then get each file-system object in the directory and pass it to the checkpermissions function:
Code:
for fsObj in "$checkdir"/*; do
      checkpermissions "$fsObj"
done
That would work with the top-level of things.
e.g. If you were only interested in the directory's immediate, top-level contents.

If full recursion is required, it would require a slightly different approach.

With the full-recursion, you'd do something like:
1. Get the name of the file/directory to check
2. Pass the object to the checkpermissions function

The checkpermissions function would deal with determining if the passed-in object is a file or a directory.
If it is a file - it outputs the permissions and returns.
If it is a directory, it uses something like my "for fsObj.." example to list the content of the directory and call checkpermissions on each object - so in other words - checkpermissions recursively calls itself each time it is passed a directory.

I hope that makes some sense!

[EDIT]
Also, what if a directory contains something that is NOT a file or a directory - like a symbolic link (which could point to a file or a directory)? Should your script ignore it? or report it?
[/EDIT]

Basically, the script should not ask for input. it should be run as ./filename and the output should be: files, dir, sub dirs and permissions. nothing asking user for input.
 

JasKinasis

Well-Known Member
Credits
848
Here's a revised version of the checkType function that will take hidden files and folders into account:
Code:
# Determine the type of object we are dealing with
checkType()
{
  if [[ -f "$1" ]]; then
     echo "$1 is a file"
      listPermissions "$1"
  elif [[ -d "$1" ]]; then
     echo "$1 is a directory"
     listPermissions "$1"
     for hidden in "$1"/.??*; do
       if [[ -e "$hidden" ]]; then
         checkType "$hidden"
       fi
     done
     for fsobj in "$1"/*; do
         checkType "$fsobj"
     done
  else
     echo "$1 is not a file or a directory!"
     listPermissions "$1"
  fi
}
There's probably a way to combine both of those regexes into a single one so we can process hidden and non-hidden files in a single loop, but it's quite late for me ATM and my brain seems to have stopped functioning - so I'll leave it at that for now!
 

JasKinasis

Well-Known Member
Credits
848
Basically, the script should not ask for input. it should be run as ./filename and the output should be: files, dir, sub dirs and permissions. nothing asking user for input.
Aaaaah crap!
I did it again and went too far! XD

OK, so you mean you run the script and wherever we are - we just make a list of everything? Or?...

I'm confused now, because in your 2nd post, you posted some code that was clearly asking the user to enter a file-name - so it appears that your script DOES require some input....

If you mean the script should not take parameters, then it would be a simple modification to scrap the parameter checking and the die function in my example script and add a read command to allow the user to manually enter the path to check.

Otherwise, if no input at all is required, it would just be a case of removing the parameter checks, remove the die function and then change the main checkType call to:
Code:
checkType $(pwd)
 


Members online


Latest posts

Top