Vincent Rodomista Vincent Rodomista - 1 year ago 42
Bash Question

accessing newly created directory in shell script

I'm attempting to make a new folder, a duplicate of the input, and then

the contents of that folder. I can't figure out why - but it seems like instead of searching the contents of my newly created directory - it is searching my entire computer... returning lines such as

/Applications/ - Vocal 1.raw is a file
/Applications/ - Vocal 2.raw is a file
/Applications/ - Arp.raw is a file
/Applications/ - Asym 4.raw is a file
/Applications/ - Eml.raw is a file
/Applications/ is a folder
/Applications/ - Arp.raw is a file
/Applications/ - Bl Saw.raw is a file

can you guys spot a simple error?

BTW, I know that the script to
isn't present yet, but that will be easy once i can navigate the new folder.


##--- deal with help args ------------------

print_help_message() {
printf "Usage: \n"
printf "\t./`basename $0` <input_dir> <output_dir>\n"
printf "where\n"
printf "\tinput_dir : (required) the input directory.\n"
printf "\toutput_dir : (required) the output directory.\n"

if [ "$1" == "help" ]; then
exit 1

## ------ get cli args ----------------------

if [ $# == 2 ]; then

## ------ tree traversal function -----------

mkdir "$2"
cp -r "$1"/* "$2"/

## ------ return output dir name ------------

return_output_dir() {
echo $OUTPUT_DIR/$(basename $(basename $(dirname $1)))

bt() {
for filename in $output_dir/*; do
if [ -d "${filename}" ]; then
echo "$filename is a folder"
bt $filename
echo "$filename is a file"

## ------ main ------------------------------

main() {
bt $return_output_dir
exit 0


Answer Source

Well, I can tell you why it's doing that, but I'm not clear on what it's supposed to be doing, so I'm not sure how to fix it. The immediate problem is that return_output_dir is a function, not a variable, so in the command bt $return_output_dir the $return_output_dir part expands to ... nothing, and bt gets run with no argument. That means that inside bt, output_dir gets set to the empty string, so for filename in $output_dir/* becomes for filename in /*, which iterates over the top-level items on your boot volume.

There are a number of other things that're confusing/weird about this code:

  • The function main() doesn't seem to serve any purpose -- some of the main-line code is outside it (notably, the argument parsing stuff), some inside, for no apparent reason. Having a main function is required in some languages, but in a shell script it generally makes more sense to just put the main code inline. (Also, functions shouldn't exit, they should return.)

  • You have variables named both OUTPUT_DIR and output_dir. Use distinct names. Also, it's generally best to stick to lowercase (or mixed-case) variable names, to avoid conflicts with the variables that're used by the shell and other programs.

  • You copy $1 and $2 into INPUT_DIR and OUTPUT_DIR, then continue to use $1 and $2 rather than the more-clearly-named variables you just copied them into.

  • output_dir is changed in the recursive function, but not declared as local; this means that inner invocations of bt will be changing the values that outer ones might try to use, leading to weirdness. Declare function-local variables as local to avoid trouble.

  • $(basename $(basename $(dirname $1))) doesn't make sense. Suppose $1 is "/foo/bar/baz/quux": then dirname $1 returns /foo/bar/baz, basename /foo/bar/baz returns "baz", and basename baz returns "baz" again. The second basename isn't doing anything! And in any case, I'm pretty sure the whole thing isn't doing what you expect it to.

  • What directory is bt supposed to be recursing through? Nothing in how you call it has any reference to either INPUT_DIR or OUTPUT_DIR.

  • As a rule, you should put variable references in double-quotes (e.g. for filename in "$output_dir"/* and bt "$filename"). You do this in some places, but not others.