- How to find,copy and rename files in linux?
- 4 Answers 4
- Linux ‘find’ command: How to find and copy files
- Another example: Find and move
- Copy all files in a directory to a local subdirectory in linux
- 3 Answers 3
- Copy via find -exec:
- Copy with extglob:
- Copy without extglob:
- find and copy all images in directory using terminal linux mint, trying to understand syntax
- 5 Answers 5
How to find,copy and rename files in linux?
I am trying to find all files in a directory and sub-directories and then copy them to a different directory. However some of them have the same name, so I need to copy the files over and then if there are two files have the same name, rename one of those files. So far I have managed to copy all found files with a unique name over using:
#!/bin/bash if [ ! -e $2 ] ; then mkdir $2 echo "Directory created" fi if [ ! -e $1 ] ; then echo "image source does not exists" fi find $1 -name IMG_****.JPG -exec cp <> $2 \;
However, I now need some sort of if statement to figure out if a file has the same name as another file that has been copied.
One * matches all, you don’t need four of them. If you want to match exactly four characters, you can do . where each ? matches only one character. Also, you need to quote «IMG_. JPG» (like I did) to prevent shell from expanding it. You probably got lucky and there is no IMG_. JPG in the directory you are calling find from, so the pattern is kept intact.
Sure! I recommend reading this page: mywiki.wooledge.org/BashPitfalls it has good information where beginners (myself included) usually get wrong with bash.
4 Answers 4
Since you are on linux, you are probably using cp from coreutils. If that is the case, let it do the backup for you by using cp —backup=t
Try this approach: put the list of files in a variable and copy each file looking if the copy operation succeeds. If not, try a different name.
FILES=`find $1 -name IMG_****.JPG | xargs -r` for FILE in $FILES; do cp -n $FILE destination # Check return error of latest command (i.e. cp) # through the $? variable and, in case # choose a different name for the destination done
Inside the for statement, you can also put some incremental integer to try different names incrementally (e.g., name_1, name_2 and so on, until the cp command succeeds).
You are right, -n is —no-clobber . I confused it with the flag from other commands. The answer is fine now.
Sorry, I should have mentioned in the question that I am only learning linux for the first time, so could you explain what the parts of your code do please? sorry.
for file in $1/**/IMG_*.jpg ; do target=$2/$(basename "$file") SUFF=0 while [[ -f "$target$SUFF" ]] ; do (( SUFF++ )) done cp "$file" "$target$SUFF" done
in your script in place of the find command to append integer suffixes to identically-named files
You can use rsync with the following switches for more control
rsync —backup —backup-dir=DIR —suffix=SUFFIX -az
-b, —backup
With this option, preexisting destination files are renamed as each file is transferred or deleted. You can control where the backup file goes and what (if any) suffix gets appended using the —backup-dir and —suffix options.
—backup-dir=DIR
In combination with the —backup option, this tells rsync to store all backups in the specified directory on the receiving side. This can be used for incremental backups. You can additionally specify a backup suffix using the —suffix option (otherwise the files backed up in the specified directory will keep their original filenames).
—suffix=SUFFIX
This option allows you to override the default backup suffix used with the —backup (-b) option. The default suffix is a ~ if no —backup-dir was specified, otherwise it is an empty string.
You can use rsycn to either sync two folders on local file system or on a remote file system. You can even do syncing over ssh connection.
rsync is amazingly powerful. See the man page for all the options.
Linux ‘find’ command: How to find and copy files
Linux find/copy FAQ: How can I use the find command to find many files and copy them all to a directory?
I ran into a situation this morning where I needed to use the Linux find command to (a) find all the MP3 files beneath my current directory and (b) copy them to another directory. In this case I didn’t want to do a cp -r command or tar command to preserve the directory structure; instead, I wanted all of the files to end up in the same directory (so I could easily import them into iTunes).
In short, here’s the find command I used to find and copy all of those files:
find . -type f -name "*.mp3" -exec cp <> /tmp/MusicFiles \;
If you’re familiar with the find command and have used the -exec option before, the only thing hard about this command is knowing where to put the curly braces and the \; in the command.
- In this example, all the MP3 files beneath the current directory are copied into the target directory (/tmp/MusicFiles). Again, this isn’t a cp -r command; all of these files will end up in one folder.
- As a result, if there are duplicate file names, some of the files will be lost.
- If you don’t want to overwrite existing files, use the cp -n command, like this:
find . -type f -name "*.mp3" -exec cp -n <> /tmp/MusicFiles \;
The -n option of the cp command means “no clobber,” and you can also type that as cp —no-clobber on some systems, such as Linux. (The -n option appears to work on MacOS systems, but —no-clobber does not.) Be sure to test this command before using it on something important; I haven’t tested it yet, I just read the man page for the cp command.)
If you ever need to use the Linux find command to find a large collection of files and copy them to another location, I hope this has been helpful.
Another example: Find and move
Here’s another example of a “find and copy” command I just used, though in this case it was a “find and move” command. In this case I had a bunch of files (with unique names) in subdirectories, and used this command to copy them all to the current directory:
As before, this is a dangerous command, so be careful. With this command, if you have duplicate filenames, you will definitely lose data during the move operations.
Copy all files in a directory to a local subdirectory in linux
I’d like to make a copy of all the existing files and directories located in this directory in new_subdir . How can I accomplish this via the linux terminal?
3 Answers 3
This is an old question, but none of the answers seem to work (they cause the destination folder to be copied recursively into itself), so I figured I’d offer up some working examples:
Copy via find -exec:
find . ! -regex ‘.*/new_subdir’ ! -regex ‘.’ -exec cp -r ‘<>‘ new_subdir \;
This code uses regex to find all files and directories (in the current directory) which are not new_subdir and copies them into new_subdir. The ! -regex ‘.’ bit is in there to keep the current directory itself from being included. Using find is the most powerful technique I know, but it’s long-winded and a bit confusing at times.
Copy with extglob:
cp -r !(new_subdir) new_subdir
If you have extglob enabled for your bash terminal (which is probably the case), then you can use ! to copy all things in the current directory which are not new_subdir into new_subdir.
Copy without extglob:
mv * new_subdir ; cp -r new_subdir/* .
If you don’t have extglob and find doesn’t appeal to you and you really want to do something hacky, you can move all of the files into the subdirectory, then recursively copy them back to the original directory. Unlike cp which copies the destination folder into itself, mv just throws an error when it tries to move the destination folder inside of itself. (But it successfully moves every other file and folder.)
find and copy all images in directory using terminal linux mint, trying to understand syntax
OS Linux Mint Like the title says finally I would like to find and copy all images in a directory. I found: find all jpg (or JPG) files in a directory and copy them into the folder /home/joachim/neu2:
find . -iname \*.jpg -print0 | xargs -I<> -0 cp -v <> /home/joachim/neu2
find . -name '*' -exec file <> \; | grep -o -P '^.+: \w+ image'
My problem is first of all, I don’t really understand the syntax. Could someone explain the code? And secondly can someone connect the two codes for generating a code that does what I want 😉 Greetings and thanks in advance!
5 Answers 5
First, understand that the pipe «|» links commands piping the output of the first into the second as an argument. Your two shell codes both pipe output of the find command into other commands (grep and xargs). Let’s look at those commands one after another:
First command: find
find is a program to «search for files in a directory hierarchy» (that is the explanation from find’s man page). The syntax is (in this case)
In both cases the search directory is . (that is the current directory). Note that it does not just search the current directory but all its subdirectories as well (the directory hierarchy).
The search pattern accepts options -name (meaning it searches for files the name of which matches the pattern given as an argument to this option) or -iname (same as name but case insensitive) among others.
The action pattern may be -print0 (print the exact filename including its position in the given search directory, i.e. the relative or absolute path to the file) or -exec (execute the given command on the file(s), the command is to be ended with «;» and every instance of «<>» is replaced by the filename).
That is, the first shell code (first part, left of the pipe)
searches all files with ending «.jpg» in the current directory hierarchy and prints their paths and names. The second one (first part)
finds all files in the current directory hierarchy and executes
on them. File is another command that determines and prints the file type (have a look at the man page for details, man file).
Second command: xargs
xargs is a command that «builds and exectues command lines from standard input» (man xargs), i.e. from the find output that is piped into xargs. The command that it builds and executes is in this case
Option -I<> defines the replacement string, i.e. every instance of <> in the command is to be replaced by the input it gets from file (that is, the filenames). Option -0 defines that input items are not terminated (seperated) by whitespace or newlines but only by a null character. This seems to be necessary when using and the standard way to deal with find output as xargs input.
The command that is built and executed is then of course the copy command with option -v (verbose) and it copies each of the filenames it gets from find to the directory.
Third command: grep
grep filters its input giving only those lines or strings that match a particular output pattern. Option -o tells grep to print only the matching string, not the entire line (see man grep), -P tells it to interpret the following pattern as a perl regexp pattern. In perl regex, ^ is the start of the line, .+ is any arbitrary string, this arbitrary should then be followed by a colon, a space, a number of alphanumeric characters (in perl regex denoted \w+) a space and the string «image». Essentially this grep command filters the file output to only output the filenames that are image files. (Read about perl regex’s for instance here: http://www.comp.leeds.ac.uk/Perl/matching.html )
The command you actually wanted
Now what you want to do is (1) take the output of the second shell command (which lists the image files), (2) bring it into the appropriate form and (3) pipe it into the xargs command from the first shell command line (which then builds and executes the copy command you wanted). So this time we have a three (actually four) stage shell command with two pipes. Not a problem. We already have stages (1) and (3) (though in stage (3) we need to leave out the -0 option because the input is not find output any more; we need it to treat newlines as item seperators).
Stage (2) is still missing. I suggest using the cut command for this. cut changes strings py splitting them into different fields (seperated by a delimiter character in the original string) that can then be rearranged. I will choose «:» as the delimiter character (this ends the filename in the grep output, option -d’:’) and tell it to give us just the first field (option -f1, essentialls: print only the filename, not the part that comes after the «:»), i.e. stage (2) would then be
And the entire command you wanted will then be:
find . -name '*' -exec file <> \; | grep -o -P '^.+: \w+ image' | cut -d':' -f1 | xargs -I<> cp -v <> /home/joachim/neu2