bash recusive copy script help


Pickle

Mega GP Mania
Joined
May 30, 2006
Messages
5,507
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}
 

Pickle

Mega GP Mania
Joined
May 30, 2006
Messages
5,507
Location
Detroit, Michigan
Website
Visit site
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"
 

ekianjo

Hardcore Member
Joined
May 7, 2012
Messages
8,261
Location
神戸市、日本 (Japan)
Can you add this between line 7 and 8 and report the output ?

            echo " detected Directory"

            echo '$file $2'
            copyfiles $file $2
 

ekianjo

Hardcore Member
Joined
May 7, 2012
Messages
8,261
Location
神戸市、日本 (Japan)
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:

ptitSeb

Serial Porter
Joined
Aug 15, 2012
Messages
8,854
Age
48
Location
France, near Lyon
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...
 

sswam

Advanced Member
Joined
Dec 16, 2009
Messages
1,393
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:

sebt3

homebrew player (P. & C.)
Joined
Sep 9, 2008
Messages
4,847
Age
40
Location
France
Website
sebt3.openpandora.org
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
 

moxie

The voice of reason, sense and exasperation
Staff member
Joined
Aug 15, 2006
Messages
2,707
Age
48
Location
South of Sweden
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.
 

Alec

Member
Joined
Mar 5, 2009
Messages
440
    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.
 

Pickle

Mega GP Mania
Joined
May 30, 2006
Messages
5,507
Location
Detroit, Michigan
Website
Visit site
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}
 
Top