Search code examples
bashsubdirectorycopying

Bash beginner: Error when tries to copy directory itself when making subdirectories


  • I have a directory with 4 directories in it.
  • I want to make a 5th directory (cx1_date) and create 4 empty directories with the same names as those of the original directory
  • I then want to copy two files from each of the original directories to the new subdirectories with their respective names
  • I think I am getting an error because it tries to copy the PWD itself (as this shows up as a result of the find call), so I tried to include an if statement but I think that it doesn't work

    now=$(date +"%m_%d_%Y")
    
    PWD="/nmr/charlie"
    
    mkdir $PWD/cx1_$now
    
    for name in $(find $PWD -maxdepth 1 -type d); do
    if [[ "$name" = "$PWD" && "$PWD" = "$name" ]];
    then 
        :
    else 
        cd $PWD/cx1_$now
        mkdir $PWD/$name
        cd $PWD/$name 
        cp file1.ext $PWD/cx1_$now/$name
        cp file2.ext $PWD/cx1_$now/$name
    fi 
    done
    

First line of the error

mkdir: cannot create directory `/nmr/charlie/cx1_05_15_2012//nmr/charlie/cx1_05_15_2012': No such file or directory

Thanking you in advance for any help you can give!

Charlie


Solution

  • The second mkdir doesn't want the $PWD:

    now=$(date +"%m_%d_%Y")
    
    DIR="/nmr/charlie"
    
    mkdir $DIR/cx1_$now
    
    for name in $(find $DIR -maxdepth 1 -type d)
    do
        if [[ "$name" != "$DIR" ]]
        then 
            (cd $DIR/cx1_$now; mkdir $name)
            (cd $DIR/$name 
             cp file1.ext $DIR/cx1_$now/$name
             cp file2.ext $DIR/cx1_$now/$name
            )
        fi
    done
    

    Also, PWD is a built-in variable; you shouldn't set it (except via the cd command).

    You don't need the symmetric test in the if; you can use != instead of = to avoid an empty then clause (OK, it contains a nice anodyne : command; you don't need it if you invert the test).

    I usually put cd operations into sub-shells; that way, I get less confused. An alternative for the second mkdir line is this, which doesn't need the cd or subshell:

    mkdir -p $DIR/cx1_$now/$name
    

    I recommend using the ISO 8601 format for dates, such as:

    now=$(date +"%Y_%m_%d")
    

    That way, the directories will sort in date order automatically.


    I still get the error:

    mkdir: cannot create directory `/nmr/charlie/directory_name_1': File exists
    /home/charlie/Desktop/scripts/test.sh: line 16: cd: /nmr/charlie//nmr/charlie/directory_name_1: No such file or directory 
    

    The problem likely means we've not filtered correctly yet. For example, each time you create a back up directory, all the previous backup directories will be backed up into the new one, which a little excessive. So, the other part of the exercise is filtering the output of find better.

    ...And we should be using the base name of the directory, and we can avoid all cd operations too:

    now=$(date +"%m_%d_%Y")
    
    DIR="/nmr/charlie"
    
    mkdir $DIR/cx1_$now
    
    for name in $(find $DIR -maxdepth 1 -type d | grep -v '/cx1_[^/]*$')
    do
        if [[ "$name" != "$DIR" ]]
        then
            targetdir=$DIR/cx1_$now/$(basename $name)
            mkdir -p $targetdir
            cp $name/file1.ext $name/file2.ext $targetdir
        fi
    done
    

    You do know about using 'sh -x script.sh' or 'bash -x script.sh' to run the script and see what it is doing. I'm not even sure that we need the if condition with the grep filtering out anything that looks like a backup directory from the list.

    I note that this only works if the directory paths are sane and contain no spaces. Things go wrong rather rapidly if you use non-portable files names (where portable names use [-_.A-Za-z0-9] only). Newlines and spaces really make a mess.

    Note that this would be simpler if you made the backup in directories under /nmr/backup/charlie or anywhere other than under /nmr/charlie itself. However, with care, it can be done in situ as requested.