How to copy all files with the same name into another directory using cp command - macos

I have directory named "Documents". In this directory I have 5 files:
User1.txt
User2.txt
User3.txt
User4.txt
User5.txt
Users-info.zip
index.html
I want to copy only those files in whose names there is a word "user" to another directory. How I can do this with cp command?

cp User* /path/to/dir try this, will be enough.
If you wish unusual way:
find . -type f -name 'User*' -print0 | xargs -0 cp -t /path/to/dir/for/copies/

For your case it is:
cp User[1-9].txt /dst_dir
We copy only files with User in the beginning, than some digit and finally .txt.

Related

How to move files including full path to a subfolder?

I've got a public folder that includes .html and non .html files in its root and subfolders. I need to move all non .html files to a subfolder of the public folder, e.g. to public/assets, preserving their full path.
So far I got something like this:
mkdir -p public/assets
find public -type f -not -name "*.html" -print0 | xargs -0I{} mv {} public/assets/
It doesn't work correctly, because it doesn't move files with full path, e.g. if there's a file public/foo/bar.js, it will be moved to public/assets/bar.js and not into public/assets/foo/bar.js.
I also tried another version:
mkdir -p public/assets
find public -type f -not -name "*.html" | sed 's#\(public\)\(.*\)#\1\2 public/assets\2#' | xargs -I% mv %
but it complains about incorrect syntax of mv command. I pass only one parameter to it, but after running sed it consists of 2 paths separated with one space, so I hoped it will treat it as 2 parameters.
It would be also great, if there was a way to remove empty folders after moving all files, but it's not necessary.
I suggest using rsync for this. Also, I would use a folder in a different location as destination. That folder can then be copied back to your public folder.
mkdir /tmp/assets
rsync -r --include="*/" --exclude="*.html" --include="*" --prune-empty-dirs public/* /tmp/assets
mv /tmp/assets public/assets

How to copy contents of a directory recursively without maintaining the directory hierarchy?

I am using Bash and I want to copy the contents of all subdirectories in the directories into a single flat-directory.
Here is an example. The input directory is:
xyz
--x1
--y1
--test1.txt
--test2.txt
--image1.jpg
--x2
--test3.txt
And I want the resultant directory to be:
abc
--test1.txt
--test2.txt
--test3.txt
--image1.jpg
Are there a combination of flags with cp command that can be used to achieve the above? The name of the files are always unique.
You can use mkdir and find:
mkdir -p abc
find ./xyz -type f -print0 | xargs -0 -I {} cp {} ./abc

Unzip Folders to Parent Directory Keeping Zipped Folder Name

I have a file structure as follows:
archives/
zips/
zipfolder1.zip
zipfolder2.zip
zipfolder3.zip
...
zipfolderN.zip
I have a script that unzips the folders to the parent directory "archives", but it is unzipping the contents of the folders to the "archives" directory. I need the zipped folders to remain as folders under the "archives" directory. The resultant file structure should look like this:
archives/
zips/
zipfolder1.zip
zipfolder2.zip
...
zipfolder1/
contents...
zipfolder2/
contents...
...
I am currently using the following:
find /home/username/archives/zips/*.zip -type f | xargs -i unzip -d ../ -q '{}'
How can I modify this line to keep the original folder names? Is it as simple as using ../*?
You could use basename to extract the zip into the desired directory:
find /home/username/archives/zips/*.zip -type f -exec sh -c 'unzip -q -d ../"$(basename "{}" .zip)" "{}"' \;

shell entering each folder and zip content

So I have some folder
|-Folder1
||-SubFolder1
||-SubFolder2
|-Folder2
||-SubFolder3
||-SubFolder4
Each subfolder contains several jpg I want to zip to the root folder...
I'm a little bit stuck on "How to enter each folder"
Here is my code:
find ./ -type f -name '*.jpg' | while IFS= read i
do
foldName=${PWD##*/}
zip ../../foldName *
done
The better would be to store FolderName+SubFolderName and give it to the zip command as name...
Zipping JPEGs (for Compression) is Usually Wasted Effort
First of all, attempting to compress already-compressed formats like JPEG files is usually a waste of time, and can sometimes result in archives that are larger than the original files. However, it is sometimes useful to do so for the convenience of having a bunch of files in a single package.
Just something to keep in mind. YMMV.
Use Find's -execdir Flag
What you need is the find utility's -execdir flag. The GNU find man page says:
-execdir command {} +
Like -exec, but the specified command is run from the subdirec‐
tory containing the matched file, which is not normally the
directory in which you started find.
For example, given the following test corpus:
cd /tmp
mkdir -p foo/bar/baz
touch foo/bar/1.jpg
touch foo/bar/baz/2.jpg
you can zip the entire set of files with find while excluding the path information with a single invocation. For example:
find /tmp/foo -name \*jpg -execdir zip /tmp/my.zip {} +
Use Zip's --junk-paths Flag
The zip utility on many systems supports a --junk-paths flag. The man page for zip says:
--junk-paths
Store just the name of a saved file (junk the path), and do not
store directory names.
So, if your find utility doesn't support -execdir, but you do have a zip that supports junking paths, you could do this instead:
find /tmp/foo -name \*jpg -print0 | xargs -0 zip --junk-paths /tmp/my.zip
You can use dirname to get the directory name of a file/directory it is located in.
You can also simplify the find command to search only for directories by using -type d. Then you should use basename to get only the name of the subdirs:
find ./*/* -type d | while read line; do
zip --junk-paths "$(basename $line)" $line/*.jpg
done
Explanation
find ./*/* -type d
will print out all directories located in ./*/* which will result in all subdirs of directories located in the current dir
while read line reads each line from the stream and stores it in the variable "line". Thus $line will be the relative path to the subdir, e.g. "Folder1/Subdir2"
"$(basename $line)" returns the only the name of the subdir, e.g. "Subdir2"
Update: add --junk-paths to the zip command if you do not want the directy paths to be stored in the zip filde
So a little check, I finally got something working:
find ./*/* -type d | while read line; do
#printf '%s\n' "$line"
zip ./"$line" "$line"/*.jpg
done
But this create un archive containing:
Subfolder.zip
Folder
|-Subfolder
||-File1.jpg
||-File2.jpg
||-File3.jpg
Instead I fold like it to be:
Subfolder.zip
|-File1.jpg
|-File2.jpg
|-File3.jpg
So I tried using basename and dirname in differnet combination...Always got some error...
And just to learn how to: what if I would like the new archive to be created in the same root directory as "Folder"?
Ok finally got it!
find ./* -name \*.zip -type f -print0 | xargs -0 rm -rf
find ./*/* -type d | while read line; do
#printf '%s\n' "$line"
zip --junk-paths ./"$line" "$line"/*.jpg
done
find . -name \*.zip -type f -mindepth 2 -exec mv -- '{}' . \;
In first row I simply remove all .zip files,
Then I zip all and in the final row I move all zip to the root directory!
Thanks everbody for your help!

Regex find and copy in bash (preserving folder structure)?

I have a folder with a bunch of log files. Each set of log files is in a folder detailing the time and date that the program was run. Inside these log folders, I've got some video files that I want to extract. All I want is the video files, nothing else. I tried using this command to only copy the video files, but it didn't work because a directory didn't exist.
.rmv is the file extension of the files I want.
$ find . -regex ".*\.rmv" -type f -exec cp '{}' /copy/to/here/'{}'
If I have a folder structure such as:
|--root
|
|--folder1
| |
| |--file.rmv
|
|--folder2
|
|--file2.rmv
How can I get it to copy to copy/to/here with it copying the structure of folder1 and folder2 in the destination directory?
cp has argument --parents
so the shortest way to do what you want is:
find root -name '*.rmv' -type f -exec cp --parents "{}" /copy/to/here \;
I would just use rsync.
The {} represents the full path of the found file, so your cp command evaluate to this sort of thing:
cp /root/folder1/file.rmv /copy/to/here/root/folder1/file.rmv
If you just drop the second {} it will instead be
cp /root/folder1/file.rmv /copy/to/here
the copy-file-to-directory form of cp, which should do the trick.
Also, instead of -regex, yor could just use the -name operand:
find root -name '*.rmv' -type f -exec cp {} /copy/to/here \;
Assuming src is your root and dst is your /copy/to/here
#!/bin/sh
find . -name *.rmv | while read f
do
path=$(dirname "$f" | sed -re 's/src(\/)?/dst\1/')
echo "$f -> $path"
mkdir -p "$path"
cp "$f" "$path"
done
putting this in cp.sh and running ./cp.sh from the directory over root
Output:
./src/folder1/file.rmv -> ./dst/folder1
./src/My File.rmv -> ./dst
./src/folder2/file2.rmv -> ./dst/folder2
EDIT: improved script version (thanks for the comment)

Resources