Making a directory and moving files into that directory that match a pattern - bash

I can pattern match files and move them into a directory using the line below. But I need to make the directory first.
(must make testdir directory first)
find . -type f -name '*-bak*' -exec mv '{}' ./testdir ';'
What I'm trying to do now is have the line of code also create the directory and move the files that match that pattern into that directory using the same line of code.

mkdir -p testdir && find . -type f -name '*-bak*' -exec mv {} testdir/ ';'
Be careful though, if you get two backups with the same name in different folders, you'll only be left with a single copy and all other copies overwritten!
EDIT: use mv -i to get prompted in that case instead of overwriting the files

Related

How to remove everything in a directory except one file in a subdirectory?

I need to delete everything in directory d1, except the file d1/d2/f1.txt. How can I do that in bash?
This works. It will delete everything, but the directories in path of f1.txt and of course the file itself.
find d1/ ! -iregex '\(d1/\|d1/d2\|d1/d2/f1.txt\)' -delete
However, I would strongly suggest against using -delete as it is permanent and mistyping a character could be disastorous...
You should try something like this instead, putting files and directories in trash folder first just in case you delete a file you don't want to delete you can recover it.
mkdir -p ~/.Trash
find d1/ ! -iregex '\(d1/\|d1/d2\|d1/d2/f1.txt\)' -exec mv {} ~/.Trash \;
Find the contents to delete except for (!) specific file:
find d1/ -type f ! -name 'd1/d2/f1.txt' -delete

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

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.

How to move files en-masse while skipping a few files and directories

I'm trying to write a shell script that moves all files except for the ones that end with .sh and .py. I also don't want to move directories.
This is what I've got so far:
cd FILES/user/folder
shopt -s extglob
mv !(*.sh|*.py) MoveFolder/ 2>/dev/null
shopt -u extglob
This moves all files except the ones that contain .sh or .py, but all directories are moved into MoveFolder as well.
I guess I could rename the folders, but other scripts already have those folders assigned for their work, so renaming might give me more trouble. I also could add the folder names but whenever someone else creates a folder, I would have to add its name to the script or it will be moved as well.
How can I improve this script to skip all folders?
Use find for this:
find -maxdepth 1 \! -type d \! -name "*.py" \! -name "*.sh" -exec mv -t MoveFolder {} +
What it does:
find: find things...
-maxdepth 1: that are in the current directory...
\! -type d: and that are not a directory...
\! -name "*.py: and whose name does not end with .py...
\! -name "*.sh: and whose name does not end with .sh...
-exec mv -t MoveFolder {} +: and move them to directory MoveFolder
The -exec flag is special: contrary to the the prior flags which were conditions, this one is an action. For each match, the + that ends the following command directs find to aggregate the file name at the end of the command, at the place marked with {}. When all the files are found, find executes the resulting command (i.e. mv -t MoveFolder file1 file2 ... fileN).
You'll have to check every element to see if it is a directory or not, as well as its extension:
for f in FILES/user/folder/*
do
extension="${f##*.}"
if [ ! -d "$f" ] && [[ ! "$extension" =~ ^(sh|py)$ ]]; then
mv "$f" MoveFolder
fi
done
Otherwise, you can also use find -type f and do some stuff with maxdepth and a regexp.
Regexp for the file name based on Check if a string matches a regex in Bash script, extension extracted through the solution to Extract filename and extension in Bash.

shell script to delete Files and sub directories from a directory in linux

I want to delete all files and sub directories created by using the specified files. I am currently using the command to delete files and directories
find . ! -name file.txt -type d -exec rm -r {} + #this is for sub directories
find . ! -name file.txt -type f -exec rm -f {} + #this is for files
It deletes all the files and sub directories when I run these command twice but I want to delete all files and directories created leaving one file at once sort. Any help is highly appreciable.
Regards
Jitendra
GNU find can directly delete files and directories:
find ! -name file.txt -delete
It will give error messages, because it cannot delete the directories up to file.txt, but everything else will still be deleted.
If you want to keep the files file1.txt, file2.txt, and file3.txt, chain the conditions like this:
find ! \( -name file1.txt -o -name file2.txt -o -name file3.txt \) -delete

Copy multiple files from one directory to multiple other directories

I have a directory structure
Dir_1
Dir_2
Dir_3
Source
. The directory Source contains the files File_1.txt and File_2.txt.
I want to copy all the files from the directory Source to all the remaining directories, in this case Dir_1, Dir_2 and Dir_3.
For this, I used
for i in $(ls -d */ | grep -v 'Source'); do echo $i | xargs -n 1 cp ./Source/*; done
. I, however, keep getting the message
cp: target ‘5’ is not a directory
It seems cp has problems with the directory names which have spaces in them. How do I resolve this (keeping the spaces in the directory names, obviously)?
Using find you could do something like this:
find . -mindepth 1 -maxdepth 1 -type d ! -name Source -exec cp Source/*.txt {} \;
This command searches the current directory for all subdirectories one level deep, excluding Source and then copies the text files into each.
Hope this helps :)

Resources