Waring on linux cmd: find . -delete -name "*.swp" - find

I try to delete all .swp file which vim created with the following command:
find . -delete -name "*.swp" .
Then my whole project is deleted...
Can anyone tell me why? and how to recover the project?
if you change the command to this:
find . -name "*.swp" -delete
it'll only delete the file it match
find . -delete -name "*.swp"equals to rm -rf *
This issue is a warning message for programmer.

find predicates and actions form a boolean expression that is evaluated left to right with short-circuiting.
Your expression:
find . -delete -name "*.swp"
is equivalent to the bash expression:
rm "$file" && [[ $file == *.swp ]]
This deletes the file, and if the deletion is successful it checks the name.
Compare this to:
# Like: find . -name "*.swp" -delete
[[ $file == *.swp ]] && rm "$file"
In this case, it checks the name. If the check passes, it deletes the file. This is what you intended.
This behavior is super useful, because it allows you to write more advanced control flow and branching:
find . -name '.git' -prune \
-o \( -name '*.xz' -exec xz -d {} \; \
-o -name '*.gz' -exec gzip -d {} \; \) \
-printf 'Successfully extracted %f\n'
This expression will skip any .git directory, run xz -d on .xz files only, gzip -d on .gz files only, and finally print a message for the files that were extracted.
As for your files, they're deleted. It's often not possible to get them back. You'll have to restore them from your backup or, if you're desperate, try to follow a file un-deletion guide for your OS and filesystem (but again, it's often not possible).

Related

Copy files based on regex to another folder but keep folder structure

I want to copy files matching a regex to another folder but while keeping part of the folder structure, All the filepaths will start with src/main/java/ buth the path before that is different for most files
I know that I can use
find . -iregex ".*HeadersConstants\.java" -exec cp {} ./destination/ \;
To copy a file but then I lose the file path in the destination dir
Are you on linux? Historically, cpio would have been an obvious choice but these days rsync is likely to be better:
find . -iregex ".*HeadersConstants\.java" |\
rsync -v --files-from=- ./ ${destination}/
It's probaby not a good idea for the destination to be inside . as your question code suggests but we can stop find looking there with:
find . -path ./destination -prune \
-o -iregex ".*HeadersConstants\.java" -print |\
rsync -v --file-from=- ./ ./destination/
(You may want to investigate why the -print is required.)
In the meantime I got it to work (probably not the cleanest way)
javaRe='(.*)\/src\/main\/java\/(.*)\/'
find . -name "HeadersConstants\.java" | while read f
do
if [[ ${f} =~ ${javaRe} ]]; then
path=${BASH_REMATCH[2]}
fullpath=${destination}${srcDir}${path}
mkdir -p "$fullpath"
cp "$f" "$fullpath"
fi
done

delete directories with find and exclude other directories

I'm attempting to delete some directories and I want to be able to exclude a directory called 'logs' from being deleted.
This is my basic find operation (without the exclusion):
# find . -type d |tail -10
./d20160124-1120-df8mfb/deployments
./d20160124-1120-df8mfb/releases
./d20160131-16993-vazqg5
./d20160131-16993-vazqg5/metadata
./d20160131-16993-vazqg5/deployments
./d20160131-16993-vazqg5/releases
./logs
./d20160203-27735-1tqbjh6
./d20160125-1120-1yccr9p
./d20160131-16993-1yf9lnc
I'm just tailing the output so that you have an idea of what's going on without taking up the whole page. :)
If I try to exlclude the logs directory with the prune command I get back no results.
root#ops-manager:/tmp/tmp# find . -type d -prune -o -name 'logs' -print
root#ops-manager:/tmp#
What am I doing wrong?
Once I get this right, I'll tack on an -exec rm rf {} \; command so I can delete those directories.
Any help here would be appreciated!
-prune always evaluates to true, which means the expression on the other side of -o is never evaluated. You need to change the order:
find . -type d -name 'logs' -prune -o -print

How to copy a file on several directories with the name *Co* (where *=wildcard)

How to copy a file to several directories of the form *Co*? or *52?
Apparently, just typing
cp fileA *Co*
won't work.
My other concern is that if a directory already contains fileA, I don't want it to be overwritten. That is, if the directory *Co* contains fileA, do NOT copy. Is there a one line solution for this, since I think writing a script with if-else is an overkill.
Thanks!
If your version of cp supports -n, you can do:
find . -name '*Co*' -exec cp -n fileA {} \;
If not:
find . -name '*Co*' -exec sh -c 'test -f $0/fileA || cp fileA $0' {} \;
Note that these will each descend recursively: if you don't want that you can limit the scope of find. To find either Co or *52, you can do:
find . \( -name '*Co*' -o -name '*52' \) -exec ...

unknown operator error while running .sh file

this is my script where it is searching all the log files and zipping it alongwith deleting the older archive.
However, when i run this script i get the following error :
./file.sh: test: unknown operator .
Code:
#Directory of archives
archive_dr="/u01/apps/weblogic/weblogic10/user_projects/archive"
#Directory of log files
logdir="/u01/apps/weblogic/weblogic10/user_projects/domains/BPM/servers/BPM_MS1/logs"
cd $archive_dr
#Removing older archived files
if [ find . \( -name '*.log0*.gz' -o \
-name '*.out0*.gz' \) ]
then
rm *.out00*.gz *.log00*.gz
fi
cd $logdir
#Search,zip and move the new archive files
if [ find . \( -name '*.log0*' -o -name '*.out0*' \) \
-atime +30 ]
then
for log_files in `find . \( \
-name '*.log0*' -o -name '*.out0*' \
\) -atime +30`
do
gzip $log_files
mv $log_files.gz /u01/a*/w*/w*/us*/archive
done
if [$? = 0]; then
echo "Logs Archieved Successfully"|
mailx -s " Logs Archieved Successfully" \
-c 'x#abc.com' y#abc.com'
fi
Please suggest where i am going wrong ?
Change:
if [ find . \( -name '*.log0*.gz' -o -name '*.out0*.gz' \) ]; then
to:
if [ "$(find . \( -name '*.log0*.gz' -o -name '*.out0*.gz' \))" ]; then
You want to run the find command and test whether it returns any output. The test command (which is what [ is an abbreviation for) doesn't execute its contents, it expects it to be an expression to test, as in if [ "$foo" = 3 ].
Note also that find recurses into subdirectories, but you rm only in the current directory. If you don't want to recurse, add the -maxdepth 1 option.
There's no need for the second if. If that find doesn't find any files, the for loop will have nothing to operate on and will just terminate immediately.
Sorry, not able to edit the post properly. But, got it running , :)
CODE
#Directory of archives
archive_dr="/u01/apps/weblogic/weblogic10/user_projects/archive"
#Directory of log files
logdir="/u01/apps/weblogic/weblogic10/user_projects/domains"
cd $archive_dr
#Removing older archived files
find . \( -name '*.log00*.gz' -o -name '*.out00*.gz' \) -exec rm {} \;
cd $logdir
#Search,zip and move the new archive files
for log_files in `find . \( -name '*.log0*' -o -name '*.out0*' \) -ctime +5`
do
gzip $log_files
mv $log_files.gz /u01/a*/w*/w*/us*/archive
done
if [ $? = 0 ]; then
echo "text"|mailx -s "test" -c abc#def.com' mno#pqr.com'
fi

Query ragarding Solaris find command with -exec option

I want to create tar file with all the output files resulting from executing find command.
I tried the following command:
find . \(-name "*.log" -o -name "*.log.*" \) -mtime +7 -exec tar cvf test.tar.gz {} \;
But it is including only the last found file in the test.tar file. How to include all files in test.tar file?
Regards
Chaitanya
Use command line substitution:
tar cf test.tar $(find . \(-name "*.log" -o -name "*.log.*" \) -mtime +7)
What this does is run the command in $() and makes the output the command line arguments of the outer command.
This uses the more modern bash notation. If you are not using bash, you can also use backticks which should work with most shells:
tar cf test.tar `find . \(-name "*.log" -o -name "*.log.*" \) -mtime +7`
While backticks are more portable, the $() notation is easier if you need to nest command line substitution.
You want to pipe the file names found by find into tar.
find . \(-name "*.log" -o -name "*.log.*" \) -mtime +7 -exec tar cvf test.tar.gz {} \;
But it is including only the last found file in the test.tar file.
That's because for every file it finds it is running a new tar command that overwrites the tar file from the previous command.
You can make find batch the files together by changing the \; to a + but if there's more
files than can be listed at once, find will still run multiple commands, each overwriting the tar file from the previous one. You could pipe the output through xargs but it has the same issue of possibly running the command multiple times. The command line substitution recommended above is the safest way I know of to do it, ensuring that tar can only be called once -- but if too many files are found, it may give an error about the command line being too long.
This one should equally work:
find . -name "*.log" -o -name "*.log.*" -mtime +7 -exec tar cvf test.tar {} +
Note the "+" at the end vs "\;".
For a reliable way when a very large number of files will match the search:
find . -name "*.log" -o -name "*.log.*" -mtime +7 > /tmp/find.out
tar cvf test.tar -I /tmp/find.out