Preserve directory structure when moving files using find












21














I have created the following script that move old days files as defined from source directory to destination directory. It is working perfectly.



#!/bin/bash

echo "Enter Your Source Directory"
read soure

echo "Enter Your Destination Directory"
read destination

echo "Enter Days"
read days



find "$soure" -type f -mtime "-$days" -exec mv {} "$destination" ;

echo "Files which were $days Days old moved from $soure to $destination"


This script moves files great, It also move files of source subdirectory, but it doesn't create subdirectory into destination directory. I want to implement this additional feature in it.



with example



/home/ketan     : source directory

/home/ketan/hex : source subdirectory

/home/maxi : destination directory


When I run this script , it also move hex's files in maxi directory, but I need that same hex should be created into maxi directory and move its files in same hex there.










share|improve this question





























    21














    I have created the following script that move old days files as defined from source directory to destination directory. It is working perfectly.



    #!/bin/bash

    echo "Enter Your Source Directory"
    read soure

    echo "Enter Your Destination Directory"
    read destination

    echo "Enter Days"
    read days



    find "$soure" -type f -mtime "-$days" -exec mv {} "$destination" ;

    echo "Files which were $days Days old moved from $soure to $destination"


    This script moves files great, It also move files of source subdirectory, but it doesn't create subdirectory into destination directory. I want to implement this additional feature in it.



    with example



    /home/ketan     : source directory

    /home/ketan/hex : source subdirectory

    /home/maxi : destination directory


    When I run this script , it also move hex's files in maxi directory, but I need that same hex should be created into maxi directory and move its files in same hex there.










    share|improve this question



























      21












      21








      21


      6





      I have created the following script that move old days files as defined from source directory to destination directory. It is working perfectly.



      #!/bin/bash

      echo "Enter Your Source Directory"
      read soure

      echo "Enter Your Destination Directory"
      read destination

      echo "Enter Days"
      read days



      find "$soure" -type f -mtime "-$days" -exec mv {} "$destination" ;

      echo "Files which were $days Days old moved from $soure to $destination"


      This script moves files great, It also move files of source subdirectory, but it doesn't create subdirectory into destination directory. I want to implement this additional feature in it.



      with example



      /home/ketan     : source directory

      /home/ketan/hex : source subdirectory

      /home/maxi : destination directory


      When I run this script , it also move hex's files in maxi directory, but I need that same hex should be created into maxi directory and move its files in same hex there.










      share|improve this question















      I have created the following script that move old days files as defined from source directory to destination directory. It is working perfectly.



      #!/bin/bash

      echo "Enter Your Source Directory"
      read soure

      echo "Enter Your Destination Directory"
      read destination

      echo "Enter Days"
      read days



      find "$soure" -type f -mtime "-$days" -exec mv {} "$destination" ;

      echo "Files which were $days Days old moved from $soure to $destination"


      This script moves files great, It also move files of source subdirectory, but it doesn't create subdirectory into destination directory. I want to implement this additional feature in it.



      with example



      /home/ketan     : source directory

      /home/ketan/hex : source subdirectory

      /home/maxi : destination directory


      When I run this script , it also move hex's files in maxi directory, but I need that same hex should be created into maxi directory and move its files in same hex there.







      bash shell-script find rename






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Dec 21 '12 at 23:34









      Gilles

      528k12810571583




      528k12810571583










      asked Dec 21 '12 at 14:26









      Ketan Patel

      87541524




      87541524






















          9 Answers
          9






          active

          oldest

          votes


















          11














          Instead of running mv /home/ketan/hex/foo /home/maxi, you'll need to vary the target directory based on the path produced by find. This is easier if you change to the source directory first and run find .. Now you can merely prepend the destination directory to each item produced by find. You'll need to run a shell in the find … -exec command to perform the concatenation, and to create the target directory if necessary.



          destination=$(cd -- "$destination" && pwd) # make it an absolute path
          cd -- "$source" &&
          find . -type f -mtime "-$days" -exec sh -c '
          mkdir -p "$0/${1%/*}"
          mv "$1" "$0/$1"
          ' "$destination" {} ;


          Note that to avoid quoting issues if $destination contains special characters, you can't just substitute it inside the shell script. You can export it to the environment so that it reaches the inner shell, or you can pass it as an argument (that's what I did). You might save a bit of execution time by grouping sh calls:



          destination=$(cd -- "$destination" && pwd) # make it an absolute path
          cd -- "$source" &&
          find . -type f -mtime "-$days" -exec sh -c '
          for x do
          mkdir -p "$0/${x%/*}"
          mv "$x" "$0/$x"
          done
          ' "$destination" {} +


          Alternatively, in zsh, you can use the zmv function, and the . and m glob qualifiers to only match regular files in the right date range. You'll need to pass an alternate mv function that first creates the target directory if necessary.



          autoload -U zmv
          mkdir_mv () {
          mkdir -p -- $3:h
          mv -- $2 $3
          }
          zmv -Qw -p mkdir_mv $source/'**/*(.m-'$days')' '$destination/$1$2'





          share|improve this answer





















          • for x do, you've got a missing ; there :). Also, I have no idea what you wanted to achieve with $0 but I'm quite convinced it would be sh :).
            – Michał Górny
            Oct 12 '14 at 19:02










          • @MichałGórny for x; do is technically not POSIX-compliant (check the grammar), but modern shells allow both for x do and for x; do; some old Bourne shells didn't grok for x; do. On modern shells, with sh -c '…' arg0 arg1 arg2 arg3, arg0 becomes $0, arg1 becomes $1, etc. If you want $0 to be sh, you need to write sh -c '…' sh arg1 arg2 arg3. Again, some Bourne shells behaved differently, but POSIX specifies this.
            – Gilles
            Oct 12 '14 at 19:11












          • pushd seems like a better choice that cd, as it less intrusive into the current environment.
            – jpmc26
            Aug 15 at 19:52



















          13














          I know find was specified, but this sounds like a job for rsync.



          I most often use the following:



          rsync -axuv --delete-after --progress Source/ Target/


          Here is a good example if you want to only move files of a particular file-type (example):



          rsync -rv --include '*/' --include '*.js' --exclude '*' --prune-empty-dirs Source/ Target/





          share|improve this answer























          • much cleaner than the others solutions :)
            – Guillaume
            May 31 '17 at 12:08






          • 1




            I found that --remove-source-files was helpful, which effectively causes files to be moved instead of copied. This is an awesome use of rsync.
            – Tom
            Aug 30 '17 at 5:27



















          3














          It's not as efficient, but the code is easier to read and understand, in my opinion, if you just copy the files and then delete afterwards.



          find /original/file/path/* -mtime +7 -exec cp {} /new/file/path/ ;
          find /original/file/path/* -mtime +7 -exec rm -rf {} ;


          Notice: Flaw discovered by @MV for automated operations:




          Using two separate operations is risky. If some files become older than 7 days
          while the copy operation is done, they won't be copied but they will be deleted
          by the delete operation. For something being done manually once this may not be
          an issue, but for automated scripts this may lead to data loss







          share|improve this answer



















          • 2




            Using two separate operations is risky. If some files become older than 7 days while the copy operation is done, they won't be copied but they will be deleted by the delete operation. For something being done manually once this may not be an issue, but for automated scripts this may lead to data loss.
            – MV.
            Dec 28 '16 at 5:47










          • The easy solution to this flaw is to run find once, save the list as a text file, and then use xargs twice to do the copy and then the delete.
            – David M. Perlman
            Feb 21 at 19:48



















          2














          you could do it using two instances of find(1)



          There's always cpio(1)



          (cd "$soure" && find … | cpio -pdVmu "$destination")


          Check the arguments for cpio. The ones I gave






          share|improve this answer



















          • 1




            This will break on any filenames with whitespace.
            – Chris Down
            Dec 21 '12 at 17:26






          • 1




            This copies files instead of moving them.
            – Gilles
            Dec 22 '12 at 0:01










          • May not be a perfect answer, but it helped me to move files preserving paths in a more or less straight forward manner (I have enough space to copy the files then delete). Upvoted
            – AhHatem
            Apr 27 '14 at 10:01





















          1














          You can do this by appending the absolute path of the file returned by find to your destination path:



          find "$soure" -type f -mtime "-$days" -print0 | xargs -0 -I {} sh -c '
          file="{}"
          destination="'"$destination"'"
          mkdir -p "$destination/${file%/*}"
          mv "$file" "$destination/$file"'





          share|improve this answer























          • Chris now its moves whole home into maxi
            – Ketan Patel
            Dec 21 '12 at 15:11










          • @K.KPatel No, it doesn't. It merely keeps your directory structure.
            – Chris Down
            Dec 21 '12 at 17:26










          • This breaks if $destination contains special characters, because it undergoes expansion in the inner shell. Maybe you meant destination=''"$destination"''? That still breaks on '. Also, this creates files such as /home/maxi/home/ketan/hex/foo instead of /home/maxi/hex/foo.
            – Gilles
            Dec 22 '12 at 0:03



















          0














          Better (fastest & without consuming storage space by doing copy instead of move), also is not affected by the file-names if they contain special characters in their names:



          export destination
          find "$soure" -type f "-$days" -print0 | xargs -0 -n 10 bash -c '
          for file in "$@"; do
          echo -n "Moving $file to $destination/"`dirname "$file"`" ... "
          mkdir -p "$destination"/`dirname "$file"`
          mv -f "$file" "$destination"/`dirname "$file"`/ || echo " fail !" && echo "done."
          done'


          Or faster, moving a bunch of files in the same time for multi-CPU, using the "parallel" command:



          echo "Move oldest $days files from $soure to $destination in parallel (each 10 files by "`parallel --number-of-cores`" jobs):"
          function move_files {
          for file in "$@"; do
          echo -n "Moving $file to $destination/"`dirname "$file"`" ... "
          mkdir -p "$destination"/`dirname "$file"`
          mv -f "$file" "$destination"/`dirname "$file"`/ || echo " fail !" && echo "done."
          done
          }
          export -f move_files
          export destination
          find "$soure" -type f "-$days" -print0 | parallel -0 -n 10 move_files


          P.S.: You have a typo, "soure" should be "source". I kept the variable name.






          share|improve this answer































            0














            Because there seem to be no really easy solution to this and I need it very often, I created this open source utility for linux (requires python): https://github.com/benapetr/smv



            There are multiple ways how you could use it to achieve what you need but probably most simple would be something like this:



             # -vf = verbose + force (doesn't stop on errors)
            smv -vf `find some_folder -type f -mtime "-$days"` target_folder


            You can additionally run it in dry mode so that it doesn't do anything but print what it would do



            smv -rvf `find some_folder -type f -mtime "-$days"` target_folder


            Or in case that list of files is too long to fit into argument line and you don't mind executing python for every single file, then



            find "$soure" -type f -mtime "-$days" -exec smv {} "$destination" ;


            Hope this will help someone






            share|improve this answer































              0














              This is less elegant but easy if the number / size of files isn't too great



              Zip your files together into a zip archive, and then unzip at the destination without the -j option. By default, zip will create the relative directory structure.






              share|improve this answer





























                0














                Try this way:



                IFS=$'n'
                for f in `find "$soure" -type f -mtime "-$days"`;
                do
                mkdir -p "$destination"/`dirname $f`;
                mv $f "$destination"/`dirname $f`;
                done





                share|improve this answer





















                  Your Answer








                  StackExchange.ready(function() {
                  var channelOptions = {
                  tags: "".split(" "),
                  id: "106"
                  };
                  initTagRenderer("".split(" "), "".split(" "), channelOptions);

                  StackExchange.using("externalEditor", function() {
                  // Have to fire editor after snippets, if snippets enabled
                  if (StackExchange.settings.snippets.snippetsEnabled) {
                  StackExchange.using("snippets", function() {
                  createEditor();
                  });
                  }
                  else {
                  createEditor();
                  }
                  });

                  function createEditor() {
                  StackExchange.prepareEditor({
                  heartbeatType: 'answer',
                  autoActivateHeartbeat: false,
                  convertImagesToLinks: false,
                  noModals: true,
                  showLowRepImageUploadWarning: true,
                  reputationToPostImages: null,
                  bindNavPrevention: true,
                  postfix: "",
                  imageUploader: {
                  brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
                  contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
                  allowUrls: true
                  },
                  onDemand: true,
                  discardSelector: ".discard-answer"
                  ,immediatelyShowMarkdownHelp:true
                  });


                  }
                  });














                  draft saved

                  draft discarded


















                  StackExchange.ready(
                  function () {
                  StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f59112%2fpreserve-directory-structure-when-moving-files-using-find%23new-answer', 'question_page');
                  }
                  );

                  Post as a guest















                  Required, but never shown

























                  9 Answers
                  9






                  active

                  oldest

                  votes








                  9 Answers
                  9






                  active

                  oldest

                  votes









                  active

                  oldest

                  votes






                  active

                  oldest

                  votes









                  11














                  Instead of running mv /home/ketan/hex/foo /home/maxi, you'll need to vary the target directory based on the path produced by find. This is easier if you change to the source directory first and run find .. Now you can merely prepend the destination directory to each item produced by find. You'll need to run a shell in the find … -exec command to perform the concatenation, and to create the target directory if necessary.



                  destination=$(cd -- "$destination" && pwd) # make it an absolute path
                  cd -- "$source" &&
                  find . -type f -mtime "-$days" -exec sh -c '
                  mkdir -p "$0/${1%/*}"
                  mv "$1" "$0/$1"
                  ' "$destination" {} ;


                  Note that to avoid quoting issues if $destination contains special characters, you can't just substitute it inside the shell script. You can export it to the environment so that it reaches the inner shell, or you can pass it as an argument (that's what I did). You might save a bit of execution time by grouping sh calls:



                  destination=$(cd -- "$destination" && pwd) # make it an absolute path
                  cd -- "$source" &&
                  find . -type f -mtime "-$days" -exec sh -c '
                  for x do
                  mkdir -p "$0/${x%/*}"
                  mv "$x" "$0/$x"
                  done
                  ' "$destination" {} +


                  Alternatively, in zsh, you can use the zmv function, and the . and m glob qualifiers to only match regular files in the right date range. You'll need to pass an alternate mv function that first creates the target directory if necessary.



                  autoload -U zmv
                  mkdir_mv () {
                  mkdir -p -- $3:h
                  mv -- $2 $3
                  }
                  zmv -Qw -p mkdir_mv $source/'**/*(.m-'$days')' '$destination/$1$2'





                  share|improve this answer





















                  • for x do, you've got a missing ; there :). Also, I have no idea what you wanted to achieve with $0 but I'm quite convinced it would be sh :).
                    – Michał Górny
                    Oct 12 '14 at 19:02










                  • @MichałGórny for x; do is technically not POSIX-compliant (check the grammar), but modern shells allow both for x do and for x; do; some old Bourne shells didn't grok for x; do. On modern shells, with sh -c '…' arg0 arg1 arg2 arg3, arg0 becomes $0, arg1 becomes $1, etc. If you want $0 to be sh, you need to write sh -c '…' sh arg1 arg2 arg3. Again, some Bourne shells behaved differently, but POSIX specifies this.
                    – Gilles
                    Oct 12 '14 at 19:11












                  • pushd seems like a better choice that cd, as it less intrusive into the current environment.
                    – jpmc26
                    Aug 15 at 19:52
















                  11














                  Instead of running mv /home/ketan/hex/foo /home/maxi, you'll need to vary the target directory based on the path produced by find. This is easier if you change to the source directory first and run find .. Now you can merely prepend the destination directory to each item produced by find. You'll need to run a shell in the find … -exec command to perform the concatenation, and to create the target directory if necessary.



                  destination=$(cd -- "$destination" && pwd) # make it an absolute path
                  cd -- "$source" &&
                  find . -type f -mtime "-$days" -exec sh -c '
                  mkdir -p "$0/${1%/*}"
                  mv "$1" "$0/$1"
                  ' "$destination" {} ;


                  Note that to avoid quoting issues if $destination contains special characters, you can't just substitute it inside the shell script. You can export it to the environment so that it reaches the inner shell, or you can pass it as an argument (that's what I did). You might save a bit of execution time by grouping sh calls:



                  destination=$(cd -- "$destination" && pwd) # make it an absolute path
                  cd -- "$source" &&
                  find . -type f -mtime "-$days" -exec sh -c '
                  for x do
                  mkdir -p "$0/${x%/*}"
                  mv "$x" "$0/$x"
                  done
                  ' "$destination" {} +


                  Alternatively, in zsh, you can use the zmv function, and the . and m glob qualifiers to only match regular files in the right date range. You'll need to pass an alternate mv function that first creates the target directory if necessary.



                  autoload -U zmv
                  mkdir_mv () {
                  mkdir -p -- $3:h
                  mv -- $2 $3
                  }
                  zmv -Qw -p mkdir_mv $source/'**/*(.m-'$days')' '$destination/$1$2'





                  share|improve this answer





















                  • for x do, you've got a missing ; there :). Also, I have no idea what you wanted to achieve with $0 but I'm quite convinced it would be sh :).
                    – Michał Górny
                    Oct 12 '14 at 19:02










                  • @MichałGórny for x; do is technically not POSIX-compliant (check the grammar), but modern shells allow both for x do and for x; do; some old Bourne shells didn't grok for x; do. On modern shells, with sh -c '…' arg0 arg1 arg2 arg3, arg0 becomes $0, arg1 becomes $1, etc. If you want $0 to be sh, you need to write sh -c '…' sh arg1 arg2 arg3. Again, some Bourne shells behaved differently, but POSIX specifies this.
                    – Gilles
                    Oct 12 '14 at 19:11












                  • pushd seems like a better choice that cd, as it less intrusive into the current environment.
                    – jpmc26
                    Aug 15 at 19:52














                  11












                  11








                  11






                  Instead of running mv /home/ketan/hex/foo /home/maxi, you'll need to vary the target directory based on the path produced by find. This is easier if you change to the source directory first and run find .. Now you can merely prepend the destination directory to each item produced by find. You'll need to run a shell in the find … -exec command to perform the concatenation, and to create the target directory if necessary.



                  destination=$(cd -- "$destination" && pwd) # make it an absolute path
                  cd -- "$source" &&
                  find . -type f -mtime "-$days" -exec sh -c '
                  mkdir -p "$0/${1%/*}"
                  mv "$1" "$0/$1"
                  ' "$destination" {} ;


                  Note that to avoid quoting issues if $destination contains special characters, you can't just substitute it inside the shell script. You can export it to the environment so that it reaches the inner shell, or you can pass it as an argument (that's what I did). You might save a bit of execution time by grouping sh calls:



                  destination=$(cd -- "$destination" && pwd) # make it an absolute path
                  cd -- "$source" &&
                  find . -type f -mtime "-$days" -exec sh -c '
                  for x do
                  mkdir -p "$0/${x%/*}"
                  mv "$x" "$0/$x"
                  done
                  ' "$destination" {} +


                  Alternatively, in zsh, you can use the zmv function, and the . and m glob qualifiers to only match regular files in the right date range. You'll need to pass an alternate mv function that first creates the target directory if necessary.



                  autoload -U zmv
                  mkdir_mv () {
                  mkdir -p -- $3:h
                  mv -- $2 $3
                  }
                  zmv -Qw -p mkdir_mv $source/'**/*(.m-'$days')' '$destination/$1$2'





                  share|improve this answer












                  Instead of running mv /home/ketan/hex/foo /home/maxi, you'll need to vary the target directory based on the path produced by find. This is easier if you change to the source directory first and run find .. Now you can merely prepend the destination directory to each item produced by find. You'll need to run a shell in the find … -exec command to perform the concatenation, and to create the target directory if necessary.



                  destination=$(cd -- "$destination" && pwd) # make it an absolute path
                  cd -- "$source" &&
                  find . -type f -mtime "-$days" -exec sh -c '
                  mkdir -p "$0/${1%/*}"
                  mv "$1" "$0/$1"
                  ' "$destination" {} ;


                  Note that to avoid quoting issues if $destination contains special characters, you can't just substitute it inside the shell script. You can export it to the environment so that it reaches the inner shell, or you can pass it as an argument (that's what I did). You might save a bit of execution time by grouping sh calls:



                  destination=$(cd -- "$destination" && pwd) # make it an absolute path
                  cd -- "$source" &&
                  find . -type f -mtime "-$days" -exec sh -c '
                  for x do
                  mkdir -p "$0/${x%/*}"
                  mv "$x" "$0/$x"
                  done
                  ' "$destination" {} +


                  Alternatively, in zsh, you can use the zmv function, and the . and m glob qualifiers to only match regular files in the right date range. You'll need to pass an alternate mv function that first creates the target directory if necessary.



                  autoload -U zmv
                  mkdir_mv () {
                  mkdir -p -- $3:h
                  mv -- $2 $3
                  }
                  zmv -Qw -p mkdir_mv $source/'**/*(.m-'$days')' '$destination/$1$2'






                  share|improve this answer












                  share|improve this answer



                  share|improve this answer










                  answered Dec 21 '12 at 23:58









                  Gilles

                  528k12810571583




                  528k12810571583












                  • for x do, you've got a missing ; there :). Also, I have no idea what you wanted to achieve with $0 but I'm quite convinced it would be sh :).
                    – Michał Górny
                    Oct 12 '14 at 19:02










                  • @MichałGórny for x; do is technically not POSIX-compliant (check the grammar), but modern shells allow both for x do and for x; do; some old Bourne shells didn't grok for x; do. On modern shells, with sh -c '…' arg0 arg1 arg2 arg3, arg0 becomes $0, arg1 becomes $1, etc. If you want $0 to be sh, you need to write sh -c '…' sh arg1 arg2 arg3. Again, some Bourne shells behaved differently, but POSIX specifies this.
                    – Gilles
                    Oct 12 '14 at 19:11












                  • pushd seems like a better choice that cd, as it less intrusive into the current environment.
                    – jpmc26
                    Aug 15 at 19:52


















                  • for x do, you've got a missing ; there :). Also, I have no idea what you wanted to achieve with $0 but I'm quite convinced it would be sh :).
                    – Michał Górny
                    Oct 12 '14 at 19:02










                  • @MichałGórny for x; do is technically not POSIX-compliant (check the grammar), but modern shells allow both for x do and for x; do; some old Bourne shells didn't grok for x; do. On modern shells, with sh -c '…' arg0 arg1 arg2 arg3, arg0 becomes $0, arg1 becomes $1, etc. If you want $0 to be sh, you need to write sh -c '…' sh arg1 arg2 arg3. Again, some Bourne shells behaved differently, but POSIX specifies this.
                    – Gilles
                    Oct 12 '14 at 19:11












                  • pushd seems like a better choice that cd, as it less intrusive into the current environment.
                    – jpmc26
                    Aug 15 at 19:52
















                  for x do, you've got a missing ; there :). Also, I have no idea what you wanted to achieve with $0 but I'm quite convinced it would be sh :).
                  – Michał Górny
                  Oct 12 '14 at 19:02




                  for x do, you've got a missing ; there :). Also, I have no idea what you wanted to achieve with $0 but I'm quite convinced it would be sh :).
                  – Michał Górny
                  Oct 12 '14 at 19:02












                  @MichałGórny for x; do is technically not POSIX-compliant (check the grammar), but modern shells allow both for x do and for x; do; some old Bourne shells didn't grok for x; do. On modern shells, with sh -c '…' arg0 arg1 arg2 arg3, arg0 becomes $0, arg1 becomes $1, etc. If you want $0 to be sh, you need to write sh -c '…' sh arg1 arg2 arg3. Again, some Bourne shells behaved differently, but POSIX specifies this.
                  – Gilles
                  Oct 12 '14 at 19:11






                  @MichałGórny for x; do is technically not POSIX-compliant (check the grammar), but modern shells allow both for x do and for x; do; some old Bourne shells didn't grok for x; do. On modern shells, with sh -c '…' arg0 arg1 arg2 arg3, arg0 becomes $0, arg1 becomes $1, etc. If you want $0 to be sh, you need to write sh -c '…' sh arg1 arg2 arg3. Again, some Bourne shells behaved differently, but POSIX specifies this.
                  – Gilles
                  Oct 12 '14 at 19:11














                  pushd seems like a better choice that cd, as it less intrusive into the current environment.
                  – jpmc26
                  Aug 15 at 19:52




                  pushd seems like a better choice that cd, as it less intrusive into the current environment.
                  – jpmc26
                  Aug 15 at 19:52













                  13














                  I know find was specified, but this sounds like a job for rsync.



                  I most often use the following:



                  rsync -axuv --delete-after --progress Source/ Target/


                  Here is a good example if you want to only move files of a particular file-type (example):



                  rsync -rv --include '*/' --include '*.js' --exclude '*' --prune-empty-dirs Source/ Target/





                  share|improve this answer























                  • much cleaner than the others solutions :)
                    – Guillaume
                    May 31 '17 at 12:08






                  • 1




                    I found that --remove-source-files was helpful, which effectively causes files to be moved instead of copied. This is an awesome use of rsync.
                    – Tom
                    Aug 30 '17 at 5:27
















                  13














                  I know find was specified, but this sounds like a job for rsync.



                  I most often use the following:



                  rsync -axuv --delete-after --progress Source/ Target/


                  Here is a good example if you want to only move files of a particular file-type (example):



                  rsync -rv --include '*/' --include '*.js' --exclude '*' --prune-empty-dirs Source/ Target/





                  share|improve this answer























                  • much cleaner than the others solutions :)
                    – Guillaume
                    May 31 '17 at 12:08






                  • 1




                    I found that --remove-source-files was helpful, which effectively causes files to be moved instead of copied. This is an awesome use of rsync.
                    – Tom
                    Aug 30 '17 at 5:27














                  13












                  13








                  13






                  I know find was specified, but this sounds like a job for rsync.



                  I most often use the following:



                  rsync -axuv --delete-after --progress Source/ Target/


                  Here is a good example if you want to only move files of a particular file-type (example):



                  rsync -rv --include '*/' --include '*.js' --exclude '*' --prune-empty-dirs Source/ Target/





                  share|improve this answer














                  I know find was specified, but this sounds like a job for rsync.



                  I most often use the following:



                  rsync -axuv --delete-after --progress Source/ Target/


                  Here is a good example if you want to only move files of a particular file-type (example):



                  rsync -rv --include '*/' --include '*.js' --exclude '*' --prune-empty-dirs Source/ Target/






                  share|improve this answer














                  share|improve this answer



                  share|improve this answer








                  edited Dec 16 at 23:21









                  ben_wing

                  1033




                  1033










                  answered Sep 18 '15 at 12:58









                  ryanjdillon

                  28428




                  28428












                  • much cleaner than the others solutions :)
                    – Guillaume
                    May 31 '17 at 12:08






                  • 1




                    I found that --remove-source-files was helpful, which effectively causes files to be moved instead of copied. This is an awesome use of rsync.
                    – Tom
                    Aug 30 '17 at 5:27


















                  • much cleaner than the others solutions :)
                    – Guillaume
                    May 31 '17 at 12:08






                  • 1




                    I found that --remove-source-files was helpful, which effectively causes files to be moved instead of copied. This is an awesome use of rsync.
                    – Tom
                    Aug 30 '17 at 5:27
















                  much cleaner than the others solutions :)
                  – Guillaume
                  May 31 '17 at 12:08




                  much cleaner than the others solutions :)
                  – Guillaume
                  May 31 '17 at 12:08




                  1




                  1




                  I found that --remove-source-files was helpful, which effectively causes files to be moved instead of copied. This is an awesome use of rsync.
                  – Tom
                  Aug 30 '17 at 5:27




                  I found that --remove-source-files was helpful, which effectively causes files to be moved instead of copied. This is an awesome use of rsync.
                  – Tom
                  Aug 30 '17 at 5:27











                  3














                  It's not as efficient, but the code is easier to read and understand, in my opinion, if you just copy the files and then delete afterwards.



                  find /original/file/path/* -mtime +7 -exec cp {} /new/file/path/ ;
                  find /original/file/path/* -mtime +7 -exec rm -rf {} ;


                  Notice: Flaw discovered by @MV for automated operations:




                  Using two separate operations is risky. If some files become older than 7 days
                  while the copy operation is done, they won't be copied but they will be deleted
                  by the delete operation. For something being done manually once this may not be
                  an issue, but for automated scripts this may lead to data loss







                  share|improve this answer



















                  • 2




                    Using two separate operations is risky. If some files become older than 7 days while the copy operation is done, they won't be copied but they will be deleted by the delete operation. For something being done manually once this may not be an issue, but for automated scripts this may lead to data loss.
                    – MV.
                    Dec 28 '16 at 5:47










                  • The easy solution to this flaw is to run find once, save the list as a text file, and then use xargs twice to do the copy and then the delete.
                    – David M. Perlman
                    Feb 21 at 19:48
















                  3














                  It's not as efficient, but the code is easier to read and understand, in my opinion, if you just copy the files and then delete afterwards.



                  find /original/file/path/* -mtime +7 -exec cp {} /new/file/path/ ;
                  find /original/file/path/* -mtime +7 -exec rm -rf {} ;


                  Notice: Flaw discovered by @MV for automated operations:




                  Using two separate operations is risky. If some files become older than 7 days
                  while the copy operation is done, they won't be copied but they will be deleted
                  by the delete operation. For something being done manually once this may not be
                  an issue, but for automated scripts this may lead to data loss







                  share|improve this answer



















                  • 2




                    Using two separate operations is risky. If some files become older than 7 days while the copy operation is done, they won't be copied but they will be deleted by the delete operation. For something being done manually once this may not be an issue, but for automated scripts this may lead to data loss.
                    – MV.
                    Dec 28 '16 at 5:47










                  • The easy solution to this flaw is to run find once, save the list as a text file, and then use xargs twice to do the copy and then the delete.
                    – David M. Perlman
                    Feb 21 at 19:48














                  3












                  3








                  3






                  It's not as efficient, but the code is easier to read and understand, in my opinion, if you just copy the files and then delete afterwards.



                  find /original/file/path/* -mtime +7 -exec cp {} /new/file/path/ ;
                  find /original/file/path/* -mtime +7 -exec rm -rf {} ;


                  Notice: Flaw discovered by @MV for automated operations:




                  Using two separate operations is risky. If some files become older than 7 days
                  while the copy operation is done, they won't be copied but they will be deleted
                  by the delete operation. For something being done manually once this may not be
                  an issue, but for automated scripts this may lead to data loss







                  share|improve this answer














                  It's not as efficient, but the code is easier to read and understand, in my opinion, if you just copy the files and then delete afterwards.



                  find /original/file/path/* -mtime +7 -exec cp {} /new/file/path/ ;
                  find /original/file/path/* -mtime +7 -exec rm -rf {} ;


                  Notice: Flaw discovered by @MV for automated operations:




                  Using two separate operations is risky. If some files become older than 7 days
                  while the copy operation is done, they won't be copied but they will be deleted
                  by the delete operation. For something being done manually once this may not be
                  an issue, but for automated scripts this may lead to data loss








                  share|improve this answer














                  share|improve this answer



                  share|improve this answer








                  edited Nov 11 '17 at 13:46









                  vektor

                  1336




                  1336










                  answered Oct 12 '14 at 18:53









                  Elliott Post

                  314




                  314








                  • 2




                    Using two separate operations is risky. If some files become older than 7 days while the copy operation is done, they won't be copied but they will be deleted by the delete operation. For something being done manually once this may not be an issue, but for automated scripts this may lead to data loss.
                    – MV.
                    Dec 28 '16 at 5:47










                  • The easy solution to this flaw is to run find once, save the list as a text file, and then use xargs twice to do the copy and then the delete.
                    – David M. Perlman
                    Feb 21 at 19:48














                  • 2




                    Using two separate operations is risky. If some files become older than 7 days while the copy operation is done, they won't be copied but they will be deleted by the delete operation. For something being done manually once this may not be an issue, but for automated scripts this may lead to data loss.
                    – MV.
                    Dec 28 '16 at 5:47










                  • The easy solution to this flaw is to run find once, save the list as a text file, and then use xargs twice to do the copy and then the delete.
                    – David M. Perlman
                    Feb 21 at 19:48








                  2




                  2




                  Using two separate operations is risky. If some files become older than 7 days while the copy operation is done, they won't be copied but they will be deleted by the delete operation. For something being done manually once this may not be an issue, but for automated scripts this may lead to data loss.
                  – MV.
                  Dec 28 '16 at 5:47




                  Using two separate operations is risky. If some files become older than 7 days while the copy operation is done, they won't be copied but they will be deleted by the delete operation. For something being done manually once this may not be an issue, but for automated scripts this may lead to data loss.
                  – MV.
                  Dec 28 '16 at 5:47












                  The easy solution to this flaw is to run find once, save the list as a text file, and then use xargs twice to do the copy and then the delete.
                  – David M. Perlman
                  Feb 21 at 19:48




                  The easy solution to this flaw is to run find once, save the list as a text file, and then use xargs twice to do the copy and then the delete.
                  – David M. Perlman
                  Feb 21 at 19:48











                  2














                  you could do it using two instances of find(1)



                  There's always cpio(1)



                  (cd "$soure" && find … | cpio -pdVmu "$destination")


                  Check the arguments for cpio. The ones I gave






                  share|improve this answer



















                  • 1




                    This will break on any filenames with whitespace.
                    – Chris Down
                    Dec 21 '12 at 17:26






                  • 1




                    This copies files instead of moving them.
                    – Gilles
                    Dec 22 '12 at 0:01










                  • May not be a perfect answer, but it helped me to move files preserving paths in a more or less straight forward manner (I have enough space to copy the files then delete). Upvoted
                    – AhHatem
                    Apr 27 '14 at 10:01


















                  2














                  you could do it using two instances of find(1)



                  There's always cpio(1)



                  (cd "$soure" && find … | cpio -pdVmu "$destination")


                  Check the arguments for cpio. The ones I gave






                  share|improve this answer



















                  • 1




                    This will break on any filenames with whitespace.
                    – Chris Down
                    Dec 21 '12 at 17:26






                  • 1




                    This copies files instead of moving them.
                    – Gilles
                    Dec 22 '12 at 0:01










                  • May not be a perfect answer, but it helped me to move files preserving paths in a more or less straight forward manner (I have enough space to copy the files then delete). Upvoted
                    – AhHatem
                    Apr 27 '14 at 10:01
















                  2












                  2








                  2






                  you could do it using two instances of find(1)



                  There's always cpio(1)



                  (cd "$soure" && find … | cpio -pdVmu "$destination")


                  Check the arguments for cpio. The ones I gave






                  share|improve this answer














                  you could do it using two instances of find(1)



                  There's always cpio(1)



                  (cd "$soure" && find … | cpio -pdVmu "$destination")


                  Check the arguments for cpio. The ones I gave







                  share|improve this answer














                  share|improve this answer



                  share|improve this answer








                  edited Dec 21 '12 at 23:59









                  Gilles

                  528k12810571583




                  528k12810571583










                  answered Dec 21 '12 at 16:15









                  Mark Lamourine

                  312




                  312








                  • 1




                    This will break on any filenames with whitespace.
                    – Chris Down
                    Dec 21 '12 at 17:26






                  • 1




                    This copies files instead of moving them.
                    – Gilles
                    Dec 22 '12 at 0:01










                  • May not be a perfect answer, but it helped me to move files preserving paths in a more or less straight forward manner (I have enough space to copy the files then delete). Upvoted
                    – AhHatem
                    Apr 27 '14 at 10:01
















                  • 1




                    This will break on any filenames with whitespace.
                    – Chris Down
                    Dec 21 '12 at 17:26






                  • 1




                    This copies files instead of moving them.
                    – Gilles
                    Dec 22 '12 at 0:01










                  • May not be a perfect answer, but it helped me to move files preserving paths in a more or less straight forward manner (I have enough space to copy the files then delete). Upvoted
                    – AhHatem
                    Apr 27 '14 at 10:01










                  1




                  1




                  This will break on any filenames with whitespace.
                  – Chris Down
                  Dec 21 '12 at 17:26




                  This will break on any filenames with whitespace.
                  – Chris Down
                  Dec 21 '12 at 17:26




                  1




                  1




                  This copies files instead of moving them.
                  – Gilles
                  Dec 22 '12 at 0:01




                  This copies files instead of moving them.
                  – Gilles
                  Dec 22 '12 at 0:01












                  May not be a perfect answer, but it helped me to move files preserving paths in a more or less straight forward manner (I have enough space to copy the files then delete). Upvoted
                  – AhHatem
                  Apr 27 '14 at 10:01






                  May not be a perfect answer, but it helped me to move files preserving paths in a more or less straight forward manner (I have enough space to copy the files then delete). Upvoted
                  – AhHatem
                  Apr 27 '14 at 10:01













                  1














                  You can do this by appending the absolute path of the file returned by find to your destination path:



                  find "$soure" -type f -mtime "-$days" -print0 | xargs -0 -I {} sh -c '
                  file="{}"
                  destination="'"$destination"'"
                  mkdir -p "$destination/${file%/*}"
                  mv "$file" "$destination/$file"'





                  share|improve this answer























                  • Chris now its moves whole home into maxi
                    – Ketan Patel
                    Dec 21 '12 at 15:11










                  • @K.KPatel No, it doesn't. It merely keeps your directory structure.
                    – Chris Down
                    Dec 21 '12 at 17:26










                  • This breaks if $destination contains special characters, because it undergoes expansion in the inner shell. Maybe you meant destination=''"$destination"''? That still breaks on '. Also, this creates files such as /home/maxi/home/ketan/hex/foo instead of /home/maxi/hex/foo.
                    – Gilles
                    Dec 22 '12 at 0:03
















                  1














                  You can do this by appending the absolute path of the file returned by find to your destination path:



                  find "$soure" -type f -mtime "-$days" -print0 | xargs -0 -I {} sh -c '
                  file="{}"
                  destination="'"$destination"'"
                  mkdir -p "$destination/${file%/*}"
                  mv "$file" "$destination/$file"'





                  share|improve this answer























                  • Chris now its moves whole home into maxi
                    – Ketan Patel
                    Dec 21 '12 at 15:11










                  • @K.KPatel No, it doesn't. It merely keeps your directory structure.
                    – Chris Down
                    Dec 21 '12 at 17:26










                  • This breaks if $destination contains special characters, because it undergoes expansion in the inner shell. Maybe you meant destination=''"$destination"''? That still breaks on '. Also, this creates files such as /home/maxi/home/ketan/hex/foo instead of /home/maxi/hex/foo.
                    – Gilles
                    Dec 22 '12 at 0:03














                  1












                  1








                  1






                  You can do this by appending the absolute path of the file returned by find to your destination path:



                  find "$soure" -type f -mtime "-$days" -print0 | xargs -0 -I {} sh -c '
                  file="{}"
                  destination="'"$destination"'"
                  mkdir -p "$destination/${file%/*}"
                  mv "$file" "$destination/$file"'





                  share|improve this answer














                  You can do this by appending the absolute path of the file returned by find to your destination path:



                  find "$soure" -type f -mtime "-$days" -print0 | xargs -0 -I {} sh -c '
                  file="{}"
                  destination="'"$destination"'"
                  mkdir -p "$destination/${file%/*}"
                  mv "$file" "$destination/$file"'






                  share|improve this answer














                  share|improve this answer



                  share|improve this answer








                  edited Dec 21 '12 at 14:50

























                  answered Dec 21 '12 at 14:35









                  Chris Down

                  79.1k14188202




                  79.1k14188202












                  • Chris now its moves whole home into maxi
                    – Ketan Patel
                    Dec 21 '12 at 15:11










                  • @K.KPatel No, it doesn't. It merely keeps your directory structure.
                    – Chris Down
                    Dec 21 '12 at 17:26










                  • This breaks if $destination contains special characters, because it undergoes expansion in the inner shell. Maybe you meant destination=''"$destination"''? That still breaks on '. Also, this creates files such as /home/maxi/home/ketan/hex/foo instead of /home/maxi/hex/foo.
                    – Gilles
                    Dec 22 '12 at 0:03


















                  • Chris now its moves whole home into maxi
                    – Ketan Patel
                    Dec 21 '12 at 15:11










                  • @K.KPatel No, it doesn't. It merely keeps your directory structure.
                    – Chris Down
                    Dec 21 '12 at 17:26










                  • This breaks if $destination contains special characters, because it undergoes expansion in the inner shell. Maybe you meant destination=''"$destination"''? That still breaks on '. Also, this creates files such as /home/maxi/home/ketan/hex/foo instead of /home/maxi/hex/foo.
                    – Gilles
                    Dec 22 '12 at 0:03
















                  Chris now its moves whole home into maxi
                  – Ketan Patel
                  Dec 21 '12 at 15:11




                  Chris now its moves whole home into maxi
                  – Ketan Patel
                  Dec 21 '12 at 15:11












                  @K.KPatel No, it doesn't. It merely keeps your directory structure.
                  – Chris Down
                  Dec 21 '12 at 17:26




                  @K.KPatel No, it doesn't. It merely keeps your directory structure.
                  – Chris Down
                  Dec 21 '12 at 17:26












                  This breaks if $destination contains special characters, because it undergoes expansion in the inner shell. Maybe you meant destination=''"$destination"''? That still breaks on '. Also, this creates files such as /home/maxi/home/ketan/hex/foo instead of /home/maxi/hex/foo.
                  – Gilles
                  Dec 22 '12 at 0:03




                  This breaks if $destination contains special characters, because it undergoes expansion in the inner shell. Maybe you meant destination=''"$destination"''? That still breaks on '. Also, this creates files such as /home/maxi/home/ketan/hex/foo instead of /home/maxi/hex/foo.
                  – Gilles
                  Dec 22 '12 at 0:03











                  0














                  Better (fastest & without consuming storage space by doing copy instead of move), also is not affected by the file-names if they contain special characters in their names:



                  export destination
                  find "$soure" -type f "-$days" -print0 | xargs -0 -n 10 bash -c '
                  for file in "$@"; do
                  echo -n "Moving $file to $destination/"`dirname "$file"`" ... "
                  mkdir -p "$destination"/`dirname "$file"`
                  mv -f "$file" "$destination"/`dirname "$file"`/ || echo " fail !" && echo "done."
                  done'


                  Or faster, moving a bunch of files in the same time for multi-CPU, using the "parallel" command:



                  echo "Move oldest $days files from $soure to $destination in parallel (each 10 files by "`parallel --number-of-cores`" jobs):"
                  function move_files {
                  for file in "$@"; do
                  echo -n "Moving $file to $destination/"`dirname "$file"`" ... "
                  mkdir -p "$destination"/`dirname "$file"`
                  mv -f "$file" "$destination"/`dirname "$file"`/ || echo " fail !" && echo "done."
                  done
                  }
                  export -f move_files
                  export destination
                  find "$soure" -type f "-$days" -print0 | parallel -0 -n 10 move_files


                  P.S.: You have a typo, "soure" should be "source". I kept the variable name.






                  share|improve this answer




























                    0














                    Better (fastest & without consuming storage space by doing copy instead of move), also is not affected by the file-names if they contain special characters in their names:



                    export destination
                    find "$soure" -type f "-$days" -print0 | xargs -0 -n 10 bash -c '
                    for file in "$@"; do
                    echo -n "Moving $file to $destination/"`dirname "$file"`" ... "
                    mkdir -p "$destination"/`dirname "$file"`
                    mv -f "$file" "$destination"/`dirname "$file"`/ || echo " fail !" && echo "done."
                    done'


                    Or faster, moving a bunch of files in the same time for multi-CPU, using the "parallel" command:



                    echo "Move oldest $days files from $soure to $destination in parallel (each 10 files by "`parallel --number-of-cores`" jobs):"
                    function move_files {
                    for file in "$@"; do
                    echo -n "Moving $file to $destination/"`dirname "$file"`" ... "
                    mkdir -p "$destination"/`dirname "$file"`
                    mv -f "$file" "$destination"/`dirname "$file"`/ || echo " fail !" && echo "done."
                    done
                    }
                    export -f move_files
                    export destination
                    find "$soure" -type f "-$days" -print0 | parallel -0 -n 10 move_files


                    P.S.: You have a typo, "soure" should be "source". I kept the variable name.






                    share|improve this answer


























                      0












                      0








                      0






                      Better (fastest & without consuming storage space by doing copy instead of move), also is not affected by the file-names if they contain special characters in their names:



                      export destination
                      find "$soure" -type f "-$days" -print0 | xargs -0 -n 10 bash -c '
                      for file in "$@"; do
                      echo -n "Moving $file to $destination/"`dirname "$file"`" ... "
                      mkdir -p "$destination"/`dirname "$file"`
                      mv -f "$file" "$destination"/`dirname "$file"`/ || echo " fail !" && echo "done."
                      done'


                      Or faster, moving a bunch of files in the same time for multi-CPU, using the "parallel" command:



                      echo "Move oldest $days files from $soure to $destination in parallel (each 10 files by "`parallel --number-of-cores`" jobs):"
                      function move_files {
                      for file in "$@"; do
                      echo -n "Moving $file to $destination/"`dirname "$file"`" ... "
                      mkdir -p "$destination"/`dirname "$file"`
                      mv -f "$file" "$destination"/`dirname "$file"`/ || echo " fail !" && echo "done."
                      done
                      }
                      export -f move_files
                      export destination
                      find "$soure" -type f "-$days" -print0 | parallel -0 -n 10 move_files


                      P.S.: You have a typo, "soure" should be "source". I kept the variable name.






                      share|improve this answer














                      Better (fastest & without consuming storage space by doing copy instead of move), also is not affected by the file-names if they contain special characters in their names:



                      export destination
                      find "$soure" -type f "-$days" -print0 | xargs -0 -n 10 bash -c '
                      for file in "$@"; do
                      echo -n "Moving $file to $destination/"`dirname "$file"`" ... "
                      mkdir -p "$destination"/`dirname "$file"`
                      mv -f "$file" "$destination"/`dirname "$file"`/ || echo " fail !" && echo "done."
                      done'


                      Or faster, moving a bunch of files in the same time for multi-CPU, using the "parallel" command:



                      echo "Move oldest $days files from $soure to $destination in parallel (each 10 files by "`parallel --number-of-cores`" jobs):"
                      function move_files {
                      for file in "$@"; do
                      echo -n "Moving $file to $destination/"`dirname "$file"`" ... "
                      mkdir -p "$destination"/`dirname "$file"`
                      mv -f "$file" "$destination"/`dirname "$file"`/ || echo " fail !" && echo "done."
                      done
                      }
                      export -f move_files
                      export destination
                      find "$soure" -type f "-$days" -print0 | parallel -0 -n 10 move_files


                      P.S.: You have a typo, "soure" should be "source". I kept the variable name.







                      share|improve this answer














                      share|improve this answer



                      share|improve this answer








                      edited Aug 16 '16 at 11:23

























                      answered Aug 16 '16 at 11:17









                      Bogdan Velcea

                      11




                      11























                          0














                          Because there seem to be no really easy solution to this and I need it very often, I created this open source utility for linux (requires python): https://github.com/benapetr/smv



                          There are multiple ways how you could use it to achieve what you need but probably most simple would be something like this:



                           # -vf = verbose + force (doesn't stop on errors)
                          smv -vf `find some_folder -type f -mtime "-$days"` target_folder


                          You can additionally run it in dry mode so that it doesn't do anything but print what it would do



                          smv -rvf `find some_folder -type f -mtime "-$days"` target_folder


                          Or in case that list of files is too long to fit into argument line and you don't mind executing python for every single file, then



                          find "$soure" -type f -mtime "-$days" -exec smv {} "$destination" ;


                          Hope this will help someone






                          share|improve this answer




























                            0














                            Because there seem to be no really easy solution to this and I need it very often, I created this open source utility for linux (requires python): https://github.com/benapetr/smv



                            There are multiple ways how you could use it to achieve what you need but probably most simple would be something like this:



                             # -vf = verbose + force (doesn't stop on errors)
                            smv -vf `find some_folder -type f -mtime "-$days"` target_folder


                            You can additionally run it in dry mode so that it doesn't do anything but print what it would do



                            smv -rvf `find some_folder -type f -mtime "-$days"` target_folder


                            Or in case that list of files is too long to fit into argument line and you don't mind executing python for every single file, then



                            find "$soure" -type f -mtime "-$days" -exec smv {} "$destination" ;


                            Hope this will help someone






                            share|improve this answer


























                              0












                              0








                              0






                              Because there seem to be no really easy solution to this and I need it very often, I created this open source utility for linux (requires python): https://github.com/benapetr/smv



                              There are multiple ways how you could use it to achieve what you need but probably most simple would be something like this:



                               # -vf = verbose + force (doesn't stop on errors)
                              smv -vf `find some_folder -type f -mtime "-$days"` target_folder


                              You can additionally run it in dry mode so that it doesn't do anything but print what it would do



                              smv -rvf `find some_folder -type f -mtime "-$days"` target_folder


                              Or in case that list of files is too long to fit into argument line and you don't mind executing python for every single file, then



                              find "$soure" -type f -mtime "-$days" -exec smv {} "$destination" ;


                              Hope this will help someone






                              share|improve this answer














                              Because there seem to be no really easy solution to this and I need it very often, I created this open source utility for linux (requires python): https://github.com/benapetr/smv



                              There are multiple ways how you could use it to achieve what you need but probably most simple would be something like this:



                               # -vf = verbose + force (doesn't stop on errors)
                              smv -vf `find some_folder -type f -mtime "-$days"` target_folder


                              You can additionally run it in dry mode so that it doesn't do anything but print what it would do



                              smv -rvf `find some_folder -type f -mtime "-$days"` target_folder


                              Or in case that list of files is too long to fit into argument line and you don't mind executing python for every single file, then



                              find "$soure" -type f -mtime "-$days" -exec smv {} "$destination" ;


                              Hope this will help someone







                              share|improve this answer














                              share|improve this answer



                              share|improve this answer








                              edited Sep 21 '16 at 14:07

























                              answered Sep 21 '16 at 14:01









                              Petr

                              51221023




                              51221023























                                  0














                                  This is less elegant but easy if the number / size of files isn't too great



                                  Zip your files together into a zip archive, and then unzip at the destination without the -j option. By default, zip will create the relative directory structure.






                                  share|improve this answer


























                                    0














                                    This is less elegant but easy if the number / size of files isn't too great



                                    Zip your files together into a zip archive, and then unzip at the destination without the -j option. By default, zip will create the relative directory structure.






                                    share|improve this answer
























                                      0












                                      0








                                      0






                                      This is less elegant but easy if the number / size of files isn't too great



                                      Zip your files together into a zip archive, and then unzip at the destination without the -j option. By default, zip will create the relative directory structure.






                                      share|improve this answer












                                      This is less elegant but easy if the number / size of files isn't too great



                                      Zip your files together into a zip archive, and then unzip at the destination without the -j option. By default, zip will create the relative directory structure.







                                      share|improve this answer












                                      share|improve this answer



                                      share|improve this answer










                                      answered Dec 12 '17 at 18:03









                                      Chris Johnson

                                      21613




                                      21613























                                          0














                                          Try this way:



                                          IFS=$'n'
                                          for f in `find "$soure" -type f -mtime "-$days"`;
                                          do
                                          mkdir -p "$destination"/`dirname $f`;
                                          mv $f "$destination"/`dirname $f`;
                                          done





                                          share|improve this answer


























                                            0














                                            Try this way:



                                            IFS=$'n'
                                            for f in `find "$soure" -type f -mtime "-$days"`;
                                            do
                                            mkdir -p "$destination"/`dirname $f`;
                                            mv $f "$destination"/`dirname $f`;
                                            done





                                            share|improve this answer
























                                              0












                                              0








                                              0






                                              Try this way:



                                              IFS=$'n'
                                              for f in `find "$soure" -type f -mtime "-$days"`;
                                              do
                                              mkdir -p "$destination"/`dirname $f`;
                                              mv $f "$destination"/`dirname $f`;
                                              done





                                              share|improve this answer












                                              Try this way:



                                              IFS=$'n'
                                              for f in `find "$soure" -type f -mtime "-$days"`;
                                              do
                                              mkdir -p "$destination"/`dirname $f`;
                                              mv $f "$destination"/`dirname $f`;
                                              done






                                              share|improve this answer












                                              share|improve this answer



                                              share|improve this answer










                                              answered Jan 26 at 8:18









                                              Alessio

                                              1011




                                              1011






























                                                  draft saved

                                                  draft discarded




















































                                                  Thanks for contributing an answer to Unix & Linux Stack Exchange!


                                                  • Please be sure to answer the question. Provide details and share your research!

                                                  But avoid



                                                  • Asking for help, clarification, or responding to other answers.

                                                  • Making statements based on opinion; back them up with references or personal experience.


                                                  To learn more, see our tips on writing great answers.





                                                  Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


                                                  Please pay close attention to the following guidance:


                                                  • Please be sure to answer the question. Provide details and share your research!

                                                  But avoid



                                                  • Asking for help, clarification, or responding to other answers.

                                                  • Making statements based on opinion; back them up with references or personal experience.


                                                  To learn more, see our tips on writing great answers.




                                                  draft saved


                                                  draft discarded














                                                  StackExchange.ready(
                                                  function () {
                                                  StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f59112%2fpreserve-directory-structure-when-moving-files-using-find%23new-answer', 'question_page');
                                                  }
                                                  );

                                                  Post as a guest















                                                  Required, but never shown





















































                                                  Required, but never shown














                                                  Required, but never shown












                                                  Required, but never shown







                                                  Required, but never shown

































                                                  Required, but never shown














                                                  Required, but never shown












                                                  Required, but never shown







                                                  Required, but never shown







                                                  Popular posts from this blog

                                                  Morgemoulin

                                                  Scott Moir

                                                  Souastre