4

My assignment is to write a bash script that reads a directory and returns the file type of each file within, including all subdirectories. Using the find command is not allowed. I've tried to implement this using essentially two for loops, but I'm getting a segmentation fault. I found that the script does work however when I pass a directory without subdirectories. Would someone be willing to look over a noob's code and tell me what's wrong? Thank you very much.

#!/bin/bash func () { for name in $1 do if [ -f "$name" ] then file "$name" elif [ -d "$name" ] then func "$1" fi done } directory="$1/*" for name in $directory do if [ -f "$name" ] then file "$name" elif [ -d "$name" ] then func "$1" fi done 
9
  • 3
    The code looks blatantly circular. func calls func with the same argument if the elif condition is met. That'll generate an infinite loop. I suspect you can do everything this script is trying to do with a one-liner: find dir/ -type f -exec file '{}' \;.
    – frabjous
    CommentedMay 16, 2022 at 16:03
  • 1
    @frabjous the OP cannot use find, that's mentioned in the question.
    – terdon
    CommentedMay 16, 2022 at 16:05
  • 1
    @frabjous please read the question. Yes, it is homework, again, that is mentioned in the question.
    – terdon
    CommentedMay 16, 2022 at 16:11
  • 1
    Do you mean func "$name" instead of func "$1"?
    – Bodo
    CommentedMay 16, 2022 at 16:12
  • 7
    @frabjous we don't have any rule against homework questions, and this is actually a great example of a good homework question: the OP clearly stated it was homework, they explained the limitations involved, and most importantly they have tried to do it themselves, they didn't just come here so we can do it for them. They tried, but are having trouble with it, so asking here is absolutely fine. The annoying ones are where the asker just dumps the assignment text and doesn't even try to solve it. Here, the OP has done everything right!
    – terdon
    CommentedMay 16, 2022 at 16:35

2 Answers 2

12

If the "$name" it's processing is a directory, you need to call func on its contents, and not the original argument, or you get an infinite loop, and hence the segfault.

Your code can be greatly reduced by using a function on the original argument, and have the function apply to each item separately. Right now you're repeating most of what happens in the function in the main body anyway.

#!/bin/bash func () { local arg="$1" if [[ -f "$arg" ]] ; then file -- "$arg" return fi if [[ -d "$arg" ]] ; then for file in "$arg"/* ; do func "$file" done fi } func "$1" 
0
    2

    The simplest approach, if you can use bash features, is to enable globstar and use that:

    shopt -s globstar for f in "$1"/**; do if [ -f "$f" ]; then file -- "$f" fi done 

    Using the logic in your original script, you just need to give it the right input:

    #!/bin/bash func () { for name in "$1"/* do if [ -f "$name" ] then file "$name" elif [ -d "$name" ] then func "$name" fi done } directory="$1" for name in "$directory"/* do if [ -f "$name" ] then file "$name" elif [ -d "$name" ] then func "$name" fi done 

    You were using func $1 instead of func $name so you were entering an endless loop which led to the segfault. Next time, just add an echo to see what you are processing, that would have shown you the error immediately.

    Also, you really don't need to repeat code like that. The whole point of functions is to avoid such repetition, so you could simply do:

    #!/bin/bash func () { for name in "$1"/* do echo "FF $name" if [ -f "$name" ] then file "$name" elif [ -d "$name" ] then func "$name" fi done } directory="$1" for name in "$directory"/* do func "$name" done 
    4
    • 2
      Hint to the OP for improvement: The "main" part of the script is nearly the same as the body of func. The whole block could be replaced with a call to func.
      – Bodo
      CommentedMay 16, 2022 at 16:19
    • @Bodo of course, I should have added that. Thanks, fixed.
      – terdon
      CommentedMay 16, 2022 at 16:31
    • A simple func $1 would be sufficient. As this looks like a homework question I originally wrote it only as a hint instead of showing the code.
      – Bodo
      CommentedMay 16, 2022 at 16:45
    • Ok, so everything's working now as it should. One follow-up question: Why do you have to append /* to the argument outside of its quotes? For example, if I replace "$"/* with "$/*" in line 3 of your second/third code snippet the script doesn't execute. I'm just confused since our prof showed us the latter variant.CommentedMay 18, 2022 at 17:26

    You must log in to answer this question.

    Start asking to get answers

    Find the answer to your question by asking.

    Ask question

    Explore related questions

    See similar questions with these tags.