bash/command line: How to copy several files in different directories at once - bash

I am trying to copy a file (let's call it list.txt) that is in several places and give it a new name. Some folders should be ignored (e.g. those containing _old)
Assume the following structure:
/data/folder1/subfolder/user/list.txt
/data/folder2/subfolder/user/list.txt
/data/folder2/subfolder_old/user/list.txt
/data/folder3/anothername/other/list.txt
/data/folder3/anothername/ignorethisfolder/list.txt
With following command I get the exact files listed that I expect:
ll /data/*/{subfolder,anothername}/{user,other}/*.txt 2>/dev/null
That's what I want to use for copying and the following:
cp /data/*/{subfolder,anothername}/{user,other}/*.txt /data/*/{subfolder, anothername}/{user,other}/*.txt_backup 2>/dev/null
Unfortunately, this does not deliver the desired result.
What should the command for the copying process be?

Unfortunately the cp command doesn't work that way, you need to copy each file independently:
for f in /data/*/{subfolder,anothername}/{user,other}/*.txt
do
cp "$f" "${f}_backup"
done

You could use the find command:
find /data -not -path "*/*_old/*" -name "list.txt" -type f -exec cp {} {}_backup \;
Explanation
find /data traverse your /data directory
-not -path "*/*_old/*" exclude any paths with a directory ending in _old
-name "list.txt" select files/directories with the name list.txt
-type f only select files
-exec cp {} {}_backup \; execute cp on all remaining matching paths the {} is replaced with the match path and the ; is needed to end the exec statement
note
You can add your 2>/dev/null if you still get errors on some results.

Related

Mac terminal how can i search in all folders and subfolders for image

How can i search for example all .png files on an external disk and copy them to another directory?
Have tried to use the cp command. Have try it but don't work for me
?
Monterey 2.2.1
cp /Volumes/Data *.png /Volumes/Data/pictures_png
cp command won't work if you need to recursively copy from the sub directories. You need to use find.
Syntax:
find $SOURCE -type f -name '*.type' -exec cp '{}' $DESTINATION ';'
In your case,
find /Volumes/Data -type f -name '*.png' -exec cp '{}' /Volumes/Data/pictures_png ';'
Here is how it works:
-type f means copy only files not directories.
-name is to provide the filename to find. Here *.png for pattern matching
-exec executes the following line for each result the above find returns.
{} will be replaced with the results from find
; terminates -exec command

Copy all empty files into a folder with command line

I am trying to copy all empty files from the home directory into a folder that is on the desktop, using this:
find ~ -empty -exec cp {} /desktop/emptyfolder \;
However, I can't make it work.
Are there any other possible solutions to achieve this? Or maybe to write a bash script that could do this?
Add -type f to the find command to force it to search for files and not directories and so:
find ~ -empty -type f -exec cp {} /desktop/emptyfolder \;

copying files from subfolders via grep shell script

I want to write a shell script to do the following :
I have a folder with many subfolders. Each of these subfolders has a *.gz file and some other files which I don't need. I want to move all .gz files into a new subfolder called needed_files (I have already created this subfolder). So I did the following :
I went to the parent folder with all the subfolder and cp /.gz > needed_files/., but this did not work. Can you suggest what I should be doing?
grep is irrelevant here. Use find:
find . ! \( -type d -name needed_files -prune \) -type f -name '*.gz' \
-exec echo mv -t needed_files {} +
POSIX equivalent of that -exec is
-exec sh -c 'echo mv "$#" needed_files' _ {} +
If its output looks good, remove echo.
Btw I noticed that the title says copy but you also say I want to move, so decide on what you exactly want to do and let me know so I can edit my answer.

finding and copying files using shell script (folder name and file name is same)

I have a directory that include several folders. I want to write a shell script to find a file in another directory that has the same name as the mentioned folders.
To clarify I have a directory that include test1 and test2 folders. I have another directory that have two files with the names of test1 and test2. My goal is to go to the directory that have folders and then get the folder names. Then by using folder name find the file that has the same name and copy it to that folder that has the same name.
I wrote the following script but it could not copy the file.
for d in /home/Documents/test/*/ ; do
find /home/Documents/binaries/ -name "$d" -type f -exec cp {} /home/Documents/test/$d \;
cd "$d"
done
$d will be set to a full path name, such as /home/Documents/test/test1/, but you only need test1 as the argument for the -name primary. You can use parameter expansion to strip the leading path from the value of $d, but it will take two steps.
for d in /home/Documents/test/*/ ; do
fname=${d##*/} # Strip /home/Documents/test/
fname=${fname%/} # Strip the trailing /
# Note that d is already the full directory name you want to use
# as the target file for `cp`
find /home/Documents/binaries/ -name "$fname" -type f -exec cp {} "$d" \;
done
The cd command doesn't seem to accomplish anything useful, since you are using absolute path names throughout.
Simpler, though, would be to change the working directory to /home/Documents/test first.
cd /home/Documents/test/
for d in */; do
find /home/Documents/binaries/ -name "$d" -type f -exec cp {} /home/Documents/test/"$d" \;
done

How to copy files recursively, rename them but keep the same extension in Bash?

I have a folder with tens of thousands of different file types. Id like to copy them all to a new folder (Copy1) but also rename them all to $RANDOM but keep the extension intact. I realize I can write a line specifying which extension to find and how to name it, but there is got to be a way to do it dynamically, because there are at least 100 file types and may be more in the future.
I have the following so far:
find ./ -name '*.*' -type f -exec bash -c 'cp "$1" "${1/\/123_//_$RANDOM}"' -- {} \;
but that puts the random number after the extension, and also it puts the all in the same folder. I cant figure out how to do the following 2 things:
1 - Keep all paths intact, but in a new root folder (Copy1)
2 - How to have name be $RANDOM.extension, instead of .extension.$RANDOM
PS - by $RANDOM i mean actual randomly generated number. I am interested in keeping folder structure, so we are dealing with a few hundred files at most per directory, but all directories/files need to be renamed to $RANDOM. Another way to look at what I need to do. Copy all contents or Folder1 with all subdirectories and files to Folder2 (where Fodler2 is a $RANDOM name), then rename all folders and files to random names but keep all extensions.
EDIT: Ok i figured out how to rename and keep extension. But I have a problem where its dumping all of the files into the root directory where script is run from. How do I keep them in their respective folders? Command Im using is:
find ./ -name '*.*' -type f -exec bash -c 'mv "$1" $RANDOM.${1##*.}' -- {} \;
Thanks!
Ok i figured out how to rename and keep extension. But I have a
problem where its dumping all of the files into the root directory
where script is run from. How do I keep them in their respective
folders? Command Im using is:
find ./ -name '*.*' -type f -exec bash -c 'mv "$1" $RANDOM.${1##*.}' -- {} \;
Change your command to:
PATH=/bin:/usr/bin find . -name '*.*' -type f -execdir bash -c 'mv "$1" $RANDOM.${1##*.}' -- {} \;
Or alternatively using uuids instead of random numbers:
PATH=/bin:/usr/bin find . -name '*.*' -type f -execdir bash -c 'mv "$1" $(uuidgen).${1##*.}' -- {} \;
Here's what I came up with :
i=1
random="whatever"
find . -name "*.*" -type f | while read f
do
newbase=${f/*./$random$i.} //added counter to filename
cp $f /Path/Name/"$newbase"
((i++))
done
I had to add a counter to random (i), otherwise, if the extensions are similar, your files would overwrite themselves when copied.
In your new folder, your files should look like this :
whatever1.txt
whatever2.txt
etc etc
I hope this is what you were looking for.
Here is the command that worked for me.
find . -name '*.pdf' -type f -exec bash -c 'echo "{}" && cp "$1" ./$RANDOM.${1##*.}' -- {} \;

Resources