find: missing argument to `-exec` - shell

I'm trying to get my Shell script working, but I keep getting: find: missing argument to '-exec'
#!/bin/sh
echo Hello World
find ./public_html/var/session/ -type f -name "sess*" -mtime +30 -exec rm -f {} \;
echo DONE
I've been trying to find help in these solutions but sadly none of them have solved my problem.Shell script - find: missing argument to `-exec' find: missing argument to -exec

Another option not involving -exec is to pipe the result to xargs and then rm on it:
find ./public_html/var/session/ -type f -name "sess*" -mtime +30 | xargs rm -f
man xargs
Note:
xargs supports executing in parallel with -P command, see man page.

Related

find -exec cant find local function "find: Log: No such file or directory"

i have a piece of code that should print all files in specific dir. i use find exec for this:
find ${_di} -type f -print -exec Log "$(stat -c%y {}) - {}" \;
Where log is function of mine defines in same file.
But id does not work and i get error message:
"find: Log: No such file or directory".
Why? What is wrong in this piece of code?
Function can't be used in -exec however bash -c can be used as command.
Slightly modified to using + as -exec command terminator and {} last to allow to reduce the number of bash processes spawned.
find ${_di} -type f -print -exec bash -c "$(typeset -f Log)"$'\n''for arg; do Log "$(stat -c%y "$arg") - $arg"; done' -- {} +
the argument -- can be replaced by anything else it is used for $0 argument of shell.
bash -c 'echo $0' hello
Maybe -printf "%TY-%Tm-%Td %TT - %p\n" option could achieve the same result, more efficiently without launching other process.
Also using echo may be less safe than using find -print option, considering the following use case.
touch file.$'\e#8'
find . -type d ! -name . -prune -o -name file'*' -print
find . -type d ! -name . -prune -o -name file'*' -exec echo {} \;
You need to export the function, and then, as Nahuel says, run bash in the -exec:
$ export -f Log
$ find ${_di} -type f -exec bash -c 'Log "$(stat -c%y {}) - {}"' bash \;

Shell stop script if find command fails

Good day.
In a script of fine i have the following find command:
find -maxdepth 1 \! -type d -name "some_file_name_*" -name "*.txt" -name "*_${day_month}_*" -exec cp {} /FILES/directory1/directory2/directory3/ +
I want to know how to stop the script if the command does't find anything.
Use GNU xargs with the -r switch and a pipeline to ensure the output of find is passed to cp only if its non-empty.
find -maxdepth 1 \! -type d -name "some_file_name_*" -name "*.txt" -name "*_${day_month}_*" \
| xargs -r I{} cp "{}" /FILES/directory1/directory2/directory3/
I{} is a place-holder for the output from the find command which is passed to cp,
The flags, -r and I{} represent the following according to the man xargs page,
-r, --no-run-if-empty
If the standard input does not contain any nonblanks, do not run
the command. Normally, the command is run once even if there is
no input. This option is a GNU extension.
-I replace-str
Replace occurrences of replace-str in the initial-arguments with
names read from standard input.
You may add -exec false {} so you get a false exit status when something is found (which makes it a bit upside-down though)
if find . -name foo -exec echo ok ';' -exec false {} +
then
echo 'not found'
exit
fi
echo found
See similar question in stackexchange: How to detect whether “find” found any matches?, in particular this answer which suggests the false trick

Error 'rm: missing operand' when using along with 'find' command

I see that this question is getting popular.
I answered my own question below.
What says Inian is correct and it helped me to analyze my source code better.
My problem was in the FIND and not in the RM. My answer gives a block of code, which I am currently using, to avoid problems when FIND finds nothing but still would pass arguments to RM, causing the error mentioned above.
OLD QUESTION BELOW
I'm writing many and many different version of the same command.
All, are executed but with an error/info:
rm: missing operand
Try 'rm --help' for more information.
These are the commands I'm using:
#!/bin/bash
BDIR=/home/user/backup
find ${BDIR} -type d -mtime +180 -print -exec rm -rf {} \;
find ${BDIR} -type d -mtime +180 -print -exec rm -rf {} +
find "$BDIR" -type d -mtime +180 -print -exec rm -rf {} \;
find "$BDIR" -depth -type d -mtime +180 -print -exec rm -rf {} \;
find ${BDIR} -depth -type d -mtime +180 -print -exec rm -rf {} +
find $BDIR -type d -mtime +180 -print0 | xargs -0 rm -rf
DEL=$(FIND $BDIR -type d -mtime +180 -print)
rm -rf $DEL
I'm sure all of them are correct (because they all do their job), and if I run them manually I do not get that message back, but while in a .sh script I do.
EDIT: since I have many of these RM's, the problem could be somewhere else. I'm checking all of them. All of the above codes works but the best answer is the one marked ;)
The problem is when using find/grep along with xargs you need to be sure to run the piped command only if the previous command is successful. Like in the above case, if the find command does not produce any search results, the rm command is invoked with an empty argument list.
The man page of xargs
-r Compatibility with GNU xargs. The GNU version of xargs runs the
utility argument at least once, even if xargs input is empty, and
it supports a -r option to inhibit this behavior. The FreeBSD
version of xargs does not run the utility argument on empty
input, but it supports the -r option for command-line compatibil-
ity with GNU xargs, but the -r option does nothing in the FreeBSD
version of xargs.
Moreover, you don't to try all the commands like you pasted the below simple one will suit your need.
Add the -r argument to xargs like
find "$BDIR" -type d -mtime +180 -print0 | xargs -0 -r rm -rf
-f option of rm suppresses the rm: missing operand error:
-f, --force
ignore nonexistent files and arguments, never prompt
After researches, the command I'm comfortable using is:
HOME=/home/user
FDEL=$HOME/foldersToDelete
BDIR=/backup/my_old_folders
FLOG=/var/log/delete_old_backup.log
find ${BDIR} -mindepth 1 -daystart -type d -mtime +180 -printf "%f\n" > ${FDEL}
if [[ $? -eq 0 && $(wc -l < ${FDEL}) -gt 0 ]]; then
cd ${BDIR}
xargs -d '\n' -a ${FDEL} rm -rf
LOG=" - Folders older than 180 were deleted"
else
LOG=" - There aren't folders older than 180 days to delete"
fi
echo ${LOG} >> ${FLOG}
Why? I search all the old folders I want to delete and print them all into a file, regardless for their naming with or without space. If the file is bigger than 0 byte this means that there are folder I want no more.
If your 'FIND' fails with a 'rm: missing operand', it probably isn't to search in the RM rather in the FIND itself.
A good way of removing the file using FIND, is the one I felt to share with you.

I am getting an error "arg list too long" in unix

i am using the following command and getting an error "arg list too long".Help needed.
find ./* \
-prune \
-name "*.dat" \
-type f \
-cmin +60 \
-exec basename {} \;
Here is the fix
find . -prune -name "*.dat" -type f -cmin +60 |xargs -i basename {} \;
To only find files in the current directory, use -maxdepth 1.
find . -maxdepth 1 -name '*.dat' -type f -cmin +60 -exec basename {} \;
In all *nix systems the shell has a maximum length of arguments that can be passed to a command. This is measured after the shell has expanded filenames passed as arguments on the command line.
The syntax of find is find location_to_find_from arguments..... so when you are running this command the shell will expand your ./* to a list of all files in the current directory. This will expand your find command line to find file1 file2 file3 etc etc This is probably not want you want as the find is recursive anyway. I expect that you are running this command in a large directory and blowing your command length limit.
Try running the command as follows
find . -name "*.dat" -type f -cmin +60 -exec basename {} \;
This will prevent the filename expansion that is probably causing your issue.
Without find, and only checking the current directory
now=$(date +%s)
for file in *.dat; do
if (( $now - $(stat -c %Y "$file") > 3600 )); then
echo "$file"
fi
done
This works on my GNU system. You may need to alter the date and stat formats for different OS's
If you have to show only .dat filename in the ./ tree. Execute it without -prune option, and use just path:
find ./ -name "*.dat" -type f -cmin +60 -exec basename {} \;
To find all the .dat files which are older than 60 minutes in the present directory only do as follows:
find . -iregex "./[^/]+\.dat" -type f -cmin +60 -exec basename {} \;
And if you have croppen (for example aix) version of find tool do as follows:
find . -name "*.dat" -type f -cmin +60 | grep "^./[^/]\+dat" | sed "s/^.\///"

find: missing argument to -exec in bash script

The following works fine when I type it exactly in the command line:
find /<some_path>/{epson,epson_laser,epson_inkjet} -iname "*.ppd"
-exec grep "\*ModelName\:" {} \; | sed 's/.*\"\(.*\)\"/\1/'
However, when I try to call the following from a
bash script I get find: missing argument to -exec'.
I have also tried the following (in many variants):
eval find "$1" -iname "*.ppd" -exec 'bash -c grep "\*ModelName\:" "$1" | sed "s/.*\"\(.*\)\"/\1/" \;
as was mentioned in find-exec-echo-missing-argument-to-exec.
How can I get to work first code not only in terminal, but also in bash script?
P.S.: I've used eval only for expanding string "/<some_path>/{epson,epson_laser,epson_inkjet}" to multiple paths. Does anyone know better solution for doing this?
If you want to execute multiple commands over the output of find, just use the -exec options as many times required:
find -exec command1 "{}" \; -exec command2 "{}" \;
You can also define the conditions to execute an option:
find \( -exec command1 \; -false -o -exec command2 \; \)
In your case, you need something like this:
find /<some_path>/{epson,epson_laser,epson_inkjet} -iname "*.ppd" -exec grep "\*ModelName\:" "{}" \; sed 's/.*\"\(.*\)\"/\1/' "{}" \;

Resources