0

I am trying to iterate over a path to a directory to run a function on all the files. Please note that this is using the Bourne Shell (/bin/sh) - NOT BASH - as that is part of the requirements I am under.

I have found resources on:

I cannot at this time get things working. The for loop executes, but it is using the string version of the basepath, when I need it to use the literal (hence bash literals ex: ${!parameter}; but I need it for Bourne).

Currently, I have:

#/bin/sh
PROJECT_NAME="Testing"
build_path=$(pwd | sed "s/${PROJECT_NAME}.*/${PROJECT_NAME}\//")
upload_folder() {
    basepath="$1/*"
    basepath="${basepath%\"}" # suffix
    basepath="${basepath#\"}"
    printf "${basepath}"
    for entry in ${basepath}; do
        echo "Entering ${entry}"
        if [ -f "$entry" ]; then
            echo "Found a file ${entry}"
            # HERE IS WHERE I WOULD RUN ANOTHER FUNCTION
        elif [ -d "$entry" ]; then
            echo "Going into folder ${entry} to upload"
            upload_folder ${entry}
        else
            echo "Nothing found"
        fi
        echo "Finished with $entry"
    done
}

upload_folder $build_path

I hope I can get some assistance here; really stuck on this one.

Spencer Pollock
  • 444
  • 4
  • 17
  • `I am trying to iterate over a path to a directory to run a function on all the files` Which files? Iterating is a mean to an end, I mean you want to run a function on each file in some directory path? This really looks like XY question. – KamilCuk Jul 22 '20 at 21:09
  • `hence bash literals ex: ${!parameter};` What do you mean by "bash literal"? I screened [bash manual](https://www.gnu.org/software/bash/manual/bash.html) and I see the word "literal" only used in a literal sense. A `${!parameter}` would be called an _indirect expansion_, why do you need it in your code? – KamilCuk Jul 22 '20 at 21:18
  • I'm looking run a function (not vital to the post; therefore not included) on each file individually. This isn't a question about doing that, it's about getting the literal value (it's using the string version) of the `basepath` variable. Apologies getting confused on the *indirect expansion* part. I'm looking to use the literal value in the `for loop`. In some tests, I used a variable with double quotes around the path and the path itself - no quotes - in the for loop, and only the latter returned any results. – Spencer Pollock Jul 22 '20 at 22:03
  • Ok. Then `basepath="${basepath%\"}" # suffix basepath="${basepath#\"}"` Why do you do that? What do you mean it does? `basepath="$1/*"` What's the point? Take some time and read https://mywiki.wooledge.org/WordSplitting – KamilCuk Jul 23 '20 at 07:13

1 Answers1

1

I see no value in creating your own recursive function. Just get the list of all files and run your callback on it:

find /some/dir -type f | while IFS= read -r file; do echo yourcallback "$file"; done

It will be safe as long as there are no newline characters in filenames.


basepath="$1/*"

Assigning * to a variable to do filename expansion later is always going to byte - because then you have to depend on word splitting. Do * on the last step.

basepath="${basepath%\"}" # suffix
basepath="${basepath#\"}"

Make no sense - why would your variable have quotes?

printf "${basepath}"

Looks very strange - basepath is not a formatting string. Do printf "%s\n" "$basepath" - the first argument is formatting specifier.

for entry in ${basepath} upload_folder ${entry} upload_folder $build_path

All unquoted variable expansions undergo word splitting, so they always will be error prone. As a rule of a thumb - always quote all expansions. Use http://shellcheck.net to find all most common mistakes in your scripts.

Just:

upload_folder() {
    for entry in "$1"/*; do
        # echo "Entering ${entry}"
        if [ -f "$entry" ]; then
            echo "Found a file $entry"
            # HERE IS WHERE I WOULD RUN ANOTHER FUNCTION
        elif [ -d "$entry" ]; then
            echo "Going into folder $entry to upload"
            upload_folder "$entry"
        else
            echo "Nothing found"
        fi
        echo "Finished with $entry"
    done
}
upload_folder "/tmp"
KamilCuk
  • 120,984
  • 8
  • 59
  • 111
  • This is a solution to get the files yes, but I am looking at fixing the variable expansion. To use my issue in your script, substitute `/some/dir` for my `basepath` variable. I cannot get my script to work with the `basepath` variable after it's passed by double quotes. I have used no-quotes and quotes and neither work. I just need to get the non-string value so that I can use it in the for loop – Spencer Pollock Jul 22 '20 at 22:05
  • The find command really did help when I started playing around with it Kami; thank you. I do not believe there is a way to get this working for bash – Spencer Pollock Jul 23 '20 at 01:42
  • `I cannot get my script to work with the basepath variable after it's passed by double quotes` I have no idea what you mean by that. Quotes are not preserved in variable assignment (I mean, unless they are), they are part of the syntax, with special meaning. [bash manual double quotes](https://www.gnu.org/software/bash/manual/bash.html#Double-Quotes) – KamilCuk Jul 23 '20 at 07:22