How to clean up directory structure from botched rsync operation? - bash

In a bash script, I am rsync'ing many directories. However, in my script I forgot to put a trailing slash at the end of the source directory. As a result, I have something like
rsync /first/path/dir /second/path/dir
in my script, which I know is wrong, and ends up creating
/second/path/dir/dir
in the destination directory, which is not what I want at all.
Is there a quick way I can use the find command to find all instances of "dir/dir" and perform an 'rm -rf' without losing the other original contents of /second/path/dir ?

you can use the -path argument to unix find command to locate (and remove) 'dir/dir'
find . -path \*/dir/dir -exec rm -rf {} \;

Related

Find and execute command on all files in directory that have a specific folder name

I want to use the find command to execute a special command on all of the files inside the directory that are contained inside multiple different directories with a specific keyword in it (the keyword is "Alpha") and keep the output inside the working directory of the initial file I ran the command on.
The command works such that it requires to you to provide the initial file to perform the command on and then the name of the newly converted file. So like this
command file_to_run_command_on.txt new_file.txt
This is my code
find $PWD -name *.txt* -exec command {} new_file. \;
Right now, it finds all the text files in this directory even in the sub directories and outputs just one file in the directory I run the initial find command from. I'm also unsure how to add the additional search for the keyword in the directory. All advice appreciated!
-exec runs the command in the directory from which you start find.
-execdir runs the command in the matching file's directory.
To only find *.txt* files whose parents contain a specific file, you could use:
find "$PWD" -path "*keyword*/*.txt*" -execdir command {} new_file \;
This will run the command for foo/bar/some-keyword-dir/baz/etc/file.txts but not for foo/bar/baz/file.txts (no keyword in parent directory names) or foo/bar/some-keyword-dir/baz/file.tar (not *.txt*)

How to move files of "specific extension" ( from directories ) to a new location while maintaining full directory structure ?

I have following directory structure :
/home/dir1/abc.jpg
/home/dir1/abc.pdf
/home/dir1/dir2/abc.jpg
/home/dir1/dir2/abc1.jpg
/home/dir1/dir2/dir3/abc.jpg
and I want to copy jpg files from them to a new folder which will have same directory structure, for eg.:
/home/newdir1/abc.jpg
/home/newdir1/dir2/abc.jpg
/home/newdir1/dir2/abc1.jpg
/home/newdir1/dir2/dir3/abc.jpg
How to achieve it using rsync or any other software ?
Please help, Many Thanks !!
From the looks of what you've included in your question, there are a couple of things you might try.
You've specified that you want to "move" files. That means you either use the mv command, or use rsync's --remove-source-files option. For example:
mv /source1/* /source2/* /path/to/targetdir/
or
rsync -a /source1/ /source2/ /path/to/targetdir/
You've no doubt already read the part of rsync's man page that explains the difference between source dirs with and without their trailing slash. If not, read up, because it's important.
If your "thousands of source files [with] similar names" need to be matched from within your source directories, leaving some other files behind, you need to determine whether your "similar names" can be differentiated using pathname expansion or if you should use a regular expression. If the former, then adding the pathname expansion to your sources with either mv or rsync should be sufficient. If you need to use a regex, then find may be a better option:
find /source1/ /source2/ -regex ".*/file[A-F][0-9][0-9].txt" -exec mv "{}" /targetdir/ \;
If these don't solve the problem, then you'll need to supply more detail in your question.
I would try a little shell script like this:
#!/bin/sh
cd /home/dir1
JPEGS=`find . -name "*.jpg"`
tar cf - $JPEGS | (cd /home/newdir1 ; tar xf -)
This first gets the list of all your jpg files with their relative paths, then writes a tar file of them to a pipe into a subshell which changes to the new directory, and then extracts the tar from its stdin.

Is it not possible to use the CLI, bash in this case, to find a set, take a set, move it, and not have to write a library to do so

I thought this would be more of a one liner to be honest.
Pretty simple in notion:
using find on Mac OS X, locate files that meet a criteria, in my case:
all file and directories in a directory:
find ~/Downloads +time1000s
That finds what I need, then I run a conditional, if a dir exists, delete it, if not, create it:
mkdir -p ~/.Trash/safe-to-delte-these-old-files
This means I need to add print0 to my find as files will have spaces, and I want to move, not copy but either way, there is a source, and a destination, and I am getting stuck:
https://gist.github.com/5c0tt/5a2c1fd39ae99d6fca05
Line 27 and 26 seem to cause me issues, I am stuck.
Suggestions on everyone from line 1 to the end. I am trying to hard to do this with POSIX in mind, but i can't even get variables to work then.
It seems BSD does not work the exact same way as other shells and what arguments they accept, which is why I am trying to be more POSIX, as I was told it should run anywhere then.
Thank you.
Took a glance at your git link, a couple of remarks if I may (still a noob tbh so may be irrelevant) :
dir_to_clean="/Users/my_username/Downloads" should probably be dir_to_clean="/Users/$current_user/Downloads" unless you actually have a literal /Users/my_username/Downloads folder.
Instead of cd'ing into your users directory and since you have hardcoded the path to that directory, you could use pushd & popd instead in order to build a stack of directories.
To answer your question, to capture files with spaces in the name for removal you could use something like :
find $dir_to_clean -not -name . +time1000s -exec mv -- {} ~/.Trash/
Could be something like this :
# Initialise variables, user, source to clean, destination
user=$(whoami);
src="/Users/$user/Downloads";
dest="~/.Trash/safe_to_delete";
# Move to directory to clean, not necessary, but if you really want to
pushd $src;
# Check if the destination exists, if not, create it
if [ ! -d $dest ]; then
mkdir -p $dest;
else
echo "destination already exists";
fi
# Find all the file to move then move them
find . -not -name . +time1000s -exec mv -- {} "$dest/" \;
# Return to previous working directory
popd;
pushd the $src directory onto the stack. find all the files in the now current directory ., -not -name . in order to avoid trying to trash the . & .. folders, -- tells find to stop parsing command line options (in cas your file/folder is named i.e. -myfile.txt), exec mv all of the arguments to $dest. popd the still current directory off of the stack. man find (/exec) for more details.
Note : It is also interesting to know that the difference of execution time between the -exec option versus results being piped into xargs can and will often be quite dramatic. Also, if your are actually sure that those files are safe_to_delete, then delete them instead of moving them (-exec rm -- {} $dest/). With all that said, you were correct, one liner.
Further reading :
http://www.softpanorama.org/Tools/Find/using_exec_option_and_xargs_in_find.shtml

Collect files from all subdirectories

I have a directory with about 5,000 subdirectories in it.
Each subdirectory contains one file each.
I'd like to collect those files and put them in the same folder somewhere.
Is there a way to do that by Mac OSX terminal command? Or should I write a, say, python script to do that?
Something like,
find . -type f -exec echo mv {} /path/to/dst/dir/ \;
You'll have to tweak this according to your circumstances, of course. See man find for details. Remove the echo when you're ready to run for real (preferably after taking a backup).

Execute command from another directory without really moving

Consider this directory structure
/dir1/Quack.sh
/dir2/ <- We are here
Is it possible to execute Quack.sh as if I were currently in /dir1/ without actually cd'ing there?
The main reason I'm asking is because Bundle is complaining when running executables who depends on it when the executable is ran from outside the folder. The executable runs fine if executed from the directory it is contained in.
You can create sub-shell and do cd, script execution:
(cd ../dir1/; ./Quack.sh)
OR else use find -execdir
find ../dir2/ -maxdepth1 -name "Quack.sh" -execdir '{}' \;

Resources