0

First post on StackOverflow, first time using Bash.

I'm currently trying to construct a function to read a file, then give me out put depending on the status:

  • If it's a file, then print the name, size and type
  • If it's a symbolic link, then print the name and it's target
  • If it's a directory, then recursively call the function on each item.
  • Otherwise return 'unknown'

I know the code is rough so far, but all I really need help with is the recursive looping part. How do I loop through the contents of a directory using a While Loop?

Here's my code so far:

#!/bin/bash

function fileChecker f  {

    if [-e $1 ]; then
        if [ -f $1]; then 
            SIZE = 'du -k $1 | cut -f1'
            CONTENT = 'file $1 | cut -d':' -f2'
            echo $1 +" " +  $SIZE + " " + $CONTENT
    elif[ -h $1 ]; then
        LINK = get info from $1
        echo $1 + " " + "symbolic link " + $LINK
    elif [ -d $1 ]; then 
        while  [ ???? ]; do  
            fileChecker n
        do
    else
        echo $1 + "unknown"
    fi
fi 
}

Thanks in advance!

3
  • 1
    You've got a bunch of bugs here (unrelated to the looping) that shellcheck.net will catch. Because this is several bugs, not one, it's not a great scope for a single question. Commented Oct 9, 2017 at 19:38
  • Could you please link to the question you mention? I'd love to take a look at it for notes... Commented Oct 10, 2017 at 19:02
  • 1
    randomir has actually done a really good job of calling out specific issues (also, if your run your code through shellcheck.net, see the wiki links in its results). That said, I did link to four questions regarding specific bugs present in the originally presented code -- see the list above, under the "This question already has an answer here:" header at the top. Commented Oct 10, 2017 at 21:00

1 Answer 1

3

There's nothing stopping you to call your function recursively, like this:

fileChecker() {
    # ...
    for f in "$1"/*; do
        fileChecker "$f"
    done
}

Here's your script with a few fixes (*), behaving as described:

#!/bin/bash
fileChecker() {
    if [ -f "$1" ]; then 
        size=$(du -k "$1" | cut -f1)
        content=$(file "$1" | cut -d':' -f2)
        echo "$1 $size $content"
    elif [ -h "$1" ]; then
        link=$(readlink -f "$1")
        echo "$1 symbolic link $link"
    elif [ -d "$1" ]; then 
        for f in "$1"/*; do
            [ -e "$f" ] || [ -h "$f" ] && fileChecker "$f"
        done
    else
        echo "$1 unknown"
    fi
}

(*) Fixes:

  • correct spacing before and after [ command
  • correct quoting of variables ("$1")
  • omitted redundant checking of file existence, since -f already checks if file exists (and is regular)
  • using command substitution $(cmd ...) instead of backticks (simpler and more readable)
  • string concat fixed in echo
  • using readlink -f for symlink target
  • POSIX-compliance (function definition)

Just note that for f in "$1"/* will not loop over filenames starting with a dot ("hidden files"). Also note the [ -e "$f" ] || [ -h "$f" ] check before a call to fileChecker to prevent calling it on "$1"/* in case the glob does not expand (when there are no files in dir "$1").

Sign up to request clarification or add additional context in comments.

15 Comments

Hmm. Might want to try to handle empty directories a bit better -- you'll get unknown printed for the nonexistent file * therein returned by the glob expression. Other than that, LGTM.
@CharlesDuffy thanks, have a look now. Any ideas for better handling (this doesn't seem too elegant)?
[ -e "$f" ] || [ -L "$f" ], if we want to recurse through symlinks whose targets don't exist. You could potentially test only the first result of "$1"/* if you wanted to (set -- "$1"/*; [ -e "$1" ] || [ -L "$1" ] || return; for arg; do fileChecker "$arg"; done), but I'm not sure if that's worth it.
Hmm, yes. But I don't think recursing over non-existing symlink is what OP wants. Other than that, look good? Thanks, Charles.
Yup, I think so. This has had my upvote for a while (since your first edit switching over to POSIX-compliant function declaration syntax).
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.