bash recusive copy script help


Pickle

Mega GP Mania
Joined
May 30, 2006
Messages
5,518
Location
Detroit, Michigan
Website
Visit site
Ive been trying to work this out, but its not working. Im trying to setup my GCW packages similar to my pnds. I put modifiable files into a folder called default. These files are copied to some location on the local fileystem, only if a file doesnt already exist.

GCW uses busybox for command implementation and it really is the bare minimum. Pandora GNU cp has a -no-clobber option which works great. Busybox cp and mv do have interactive modes....that dont work.

So im trying to use bash test arguments to detect folders and files to recursive copy my folder. So calling out there to script experts to show me the way if possible. Im open to alternative, if another command can do it ill try it (ive tried some things with rsync too).

Code:
copyfiles()
{   
    for file in $1/*; do
        echo "Checking $file"

        if [ -d $file ]; then
            echo " detected Directory"
            copyfiles $file $2
        else
            if [ -f $2/$file ]; then
                echo " Copy not writing $2/$file"
            else
                echo " Copy writing $2/$file"
                cp $1/$file $2/$file
            fi
        fi
    done
}

echo "Checking local files"
copyfiles default ${HOME}
 
the paths arnt working out right


Checking local files
Checking default/id1
 detected Directory
Checking default/id1/*
 Copy writing /usr/local/home/default/id1/*
cp: can't stat 'default/id1/default/id1/*': No such file or directory
it found the id1 directory fine, so then it went into it as expected. Im not sure how the * made it into file. Might be there wasnt a file yet in the directory.

It also is not seeing the .quake1 folder, but i think this might be fixed by adding a "for file in $1/.*; do"
 
Can you add this between line 7 and 8 and report the output ?

            echo " detected Directory"

            echo '$file $2'
            copyfiles $file $2
 
Wait, be careful if your directories have spaces in their names! This is something that requries ' ' in bash, if not they will not be handled correctly. I am assuming this may be the problem with "local files" -> space in directory name...
 
Last edited by a moderator:
I think you'll need to change from


cp $1/$file $2/$file

 
to


cp $file $2/$(basename "$file")

 
But I don't know if it works on busybox...
 
If the interactive mode does work, you can try this


yes n | cp -ia $from $to
but $to needs to be a parent folder I think
 
Last edited by a moderator:
Your issue here is that $1/* will not be interpreted as just "file" but as "$1/file". (You also forgot to create directory when encontering one, pass the directory name when recursing and to protect against spaces in filenames)2 options :

Use only filename:


copyfiles()
{   
    for file in $(ls -1 "$1"); do
        echo "Checking $file"

        if [ -d "$1/$file" ]; then
            echo " detected Directory"
mkdir "$2/$file"
            copyfiles "$1/$file" "$2/$file"
        else
            if [ -f "$2/$file" ]; then
                echo " Copy not writing $2/$file"
            else
                echo " Copy writing $2/$file"
                cp "$1/$file" "$2/$file"
            fi
        fi
    done
}

echo "Checking local files"
copyfiles default ${HOME}or using basename:
Code:
copyfiles()
{   
    for file in "$1"/*; do
        echo "Checking $file"

        if [ -d "$file" ]; then
            echo " detected Directory"
            mkdir "$2/$(basename "$file")"
            copyfiles "$file" "$2/$(basename "$file")"
        else
            if [ -f "$2/$(basename "$file")" ]; then
                echo " Copy not writing $2/$(basename "$file")"
            else
                echo " Copy writing $2/$(basename "$file")"
                cp "$file" "$2/$(basename "$file")"
            fi
        fi
    done
}

echo "Checking local files"
copyfiles default ${HOME}
beside Dredd option should work too but wont be that clean :)
PS: warning untested code
 
Because he doesn't want the script to copy over already existing files. Which is what you use --noclobber for, but that does not exist in busybox:s shell implementation.
 
    for file in $(ls -1 "$1"); do

Don't ever do that - it's always going to screw up on filenames with spaces.

If you don't have basename, you can do this on any POSIX shell:


file="${path##*/}"

It's also faster than with basename because it does not need to run another program.
 
everyone thanks for the ideas, i ended up deviating from the original script as it didnt appear it would work for hidden files as well. Google searching led me to something using find. Adding a pipe to read handles the space name problem.

this works and i dont have to recursive since the find list gives everything under the path given.

feel free to critique or suggest any improvements.

Code:
#!/bin/sh

copyfiles()
{       
    find "$1" -path '*/*'|while read file; do
    
        # Removes the source folder (default)
        output=$2${file##$1}
        
        if [ -d "$file" ]; then
            echo " Creating directory: $output"
            mkdir "$output"
        else
            if [ -f "$output" ]; then
                echo " File exists NO COPY: $output"
            else
                echo " Copying: $file to $output"
                cp "$file" "$output"
            fi
        fi
    done
}

echo "Checking default opk files"
copyfiles default ${HOME}
 
Back
Top