Shell script - find: missing argument to `-exec' - bash

I'm trying to run this script:
alias logs="cd L:/"
find $logs -name '*system.log*' -mtime +14 -exec rm {} \;
But get this error: find: missing argument to `-exec'. I've tried looking at other posts on this but can't get it working. I'm using cygwin to run this script on Windows.

If you have created any alias with name log, then to use it, you should be using $logs and not logs
Also, maybe the find you are using is of Windows and not of Cygwin. This is made clear if you type 'which find'

First, some minor fixes:
#!/bin/sh
logs=/cygdrive/l
find "$logs" -name '*system.log*' -mtime +14 -exec rm -- {} +
...but those won't address your real problem (the one causing -exec to report an error), which is almost certainly the presence of DOS newlines in your script.
find -exec reports the error in question when it doesn't see an argument containing only the exact string ;. Outside quotes, \; should be that argument -- but it can be different if your file has hidden characters. And a DOS text file will appear to have hidden characters when opened by a program expecting a UNIX text file, because the two formats have different line separators.
To fix this, open the file in a native-UNIX editor such as vim, run :set fileformat=unix, and save it; or use dos2unix to convert it in-place.

Related

How to 'cd' to the output of the 'find' command in terminal

Pretty much I want to cd to the output of the find command:
find ~ -name work_project_linux
cd the_output
In general the best way to execute an arbitrary command on the results of find is with find -exec. Curly braces {} are placeholders for the file names it finds, and the entire command ends with + or \;. For example, this will run ls -l on all of the files found:
find ~ -name work_project_linux -exec ls -l {} +
It doesn't work with some special commands like cd, though. -exec runs binaries, such as those found in /usr/bin, and cd isn't a binary. It's a shell builtin, a special type of command that the shell executes directly instead of calling out to some executable on disk. For shell builtins you can use command substitution:
cd "$(find ~ -name work_project_linux)"
This wouldn't work if find finds multiple files. It's only good for a single file name. Command substitution also won't handle some unusual file names correctly, such as those with embedded newlines—unusual, but legal.

how can i copy all the xml files which is having current date as filename from all directories

I want to copy all the xml files which is having current date as file name from all directories. Below is the script i have written.
#!/bin/bash
CURRENT_DATE=`date +'%d%m%Y'`
Temp_Path=/appinfprd/bi/infogix/IA83/InfogixClient/Scripts/IRP/New_Vendors/
FILE_PATH=/bishare/DLSFTP/DLSTREAM/
FILE_DATE=`date -d "-2 days" +"%Y%m%d"`
cd $FILE_PATH
find . -name '*$FILE_DATE*.xml' -exec cp $Temp_Path
But it is not working.
Your find statement is wrong. You should end it with \; to indicate the end of the exec command and put {} where the name of your file found should come in the command. So, you want :
find . -name "*$FILE_DATE*.xml" -exec cp "{}" "$Temp_Path" \;
Edit
As stated in the comments, there were also a problem in your initial post with your single quotes that should be double quotes. You might be interested by this man page. In particular by these sections :
-exec command ;
Execute command; true if 0 status is returned. All following arguments to find are taken to be arguments to the command until an argument consisting of ; is encountered. The string {} is replaced by the current file name being processed everywhere it occurs in the arguments to the command, not just in arguments where it is alone, as in some versions of find. Both of these constructions might need to be escaped (with a \) or quoted to protect them from expansion by the shell. See the EXAMPLES section for examples of the use of the -exec option. The specified command is run once for each matched file. The command is executed in the starting directory. There are unavoidable security problems surrounding use of the -exec action; you should use the -execdir option instead.
-exec command {} +
This variant of the -exec action runs the specified command on the selected files, but the command line is built by appending each selected file name at the end; the total number of invocations of the command will be much less than the number of matched files. The command line is built in much the same way that xargs builds its command lines. Only one instance of {} is allowed within the command, and (when find is being invoked from a shell) it should be quoted (for example, '{}') to protect it from interpretation by shells. The command is executed in the starting directory. If any invocation returns a non-zero value as exit status, then find returns a non-zero exit status. If find encounters an error, this can sometimes cause an immediate exit, so some pending commands may not be run at all. This variant of -exec always returns true.

Linux command to copy recently created/updated files?

I want to copy recently created/updated files to another folder. Say, for eg, the files which created in last 3 days should be copied to another folder(/tmp). how to do that? Is it possible.
You can use the find command's mtime argument to find files that were last modified by a certain time and then use it's exec argument to copy them somewhere.
For example, this command will find files modified within three days in your current directory and copy them to your /tmp directory:
find . -mtime -3 -type f -exec cp "{}" /tmp \;
-mtime n File's data was last modified n*24 hours ago. See the comments for -atime to understand how rounding affects the
interpretation of file modification times.
-exec command ; Execute command; true if 0 status is returned. All following arguments to find are taken to be arguments to the command
until an argument consisting of ';' is encountered. The string '{}' is
replaced by the current file name being processed everywhere it occurs
in the arguments to the command, not just in arguments where it is
alone, as in some versions of find. Both of these constructions might
need to be escaped (with a '\') or quoted to protect them from
expansion by the shell. See the EXAMPLES section for examples of the
use of the -exec option. The specified command is run once for each
matched file. The command is executed in the starting directory. There
are unavoidable security problems surrounding use of the -exec action;
you should use the -execdir option instead.

Bash find: changing matched name for use in -exec

I'm writing a deploy script, and I need to run a less compiler against all .less files in a directory. This is easy to do with the following find command:
find -name "*.less" -exec plessc {} {}.css \;
After running this command on a folder with a file named main.less, I'm left with a file named main.less.css, but I want it to be main.css.
I know I can easily strip the .less portion of the resulting files with this command: rename 's/\.less//' *.css but I'm hoping to learn something new about using -exec.
Is it possible to modify the name of the file that matches while using it in the -exec parameter?
Thanks!
Your find command is using a couple of non standard GNU extensions:
You do not state where to find, this is an error in POSIX but GNU find select the current directory in that case
You use a non isolated {}, POSIX find doesn't expand it in that case.
Here is a one liner that should work with most find implementations and fix your double extension issue:
find . -name "*.less" -exec sh -c "plessc \$0 \$(dirname \$0)/\$(basename \$0 less)css" {} \;
On Solaris 10 and older, sh -c should be replaced by ksh -c if the PATH isn't POSIX compliant.
No, it is not possible to do it directly. You can only use {} to directly insert the full filename. However, in exec, you COULD put in other things like awk. Or you can redirect output to another program via pipes.
From the find man page:
-exec command ;
Execute command; true if 0 status is returned. All following
arguments to find are taken to be arguments to the command until
an argument consisting of `;' is encountered. The string `{}'
is replaced by the current file name being processed everywhere
it occurs in the arguments to the command, not just in arguments
where it is alone, as in some versions of find. Both of these
constructions might need to be escaped (with a `\') or quoted to
protect them from expansion by the shell. See the EXAMPLES
section for examples of the use of the -exec option. The
specified command is run once for each matched file. The command
is executed in the starting directory. There are unavoidable
security problems surrounding use of the -exec action; you
should use the -execdir option instead.

Unable to understand the syntax of the command find

The find command seems to differ from other Unix commands.
Why is there the empty curly brackets and a backward flash at the end of the following command?
find * -perm 777 -exec chmod 770 {} \;
I found one reason for the curly brackets but not for the backward flash.
The curly brackets are apparently for the path
Same as -exec, except that ``{}'' is
replaced with as many pathnames as
possible for each invocation of
utility
The -exec command may be followed by any number of arguments that make up the command that is to be executed for each file found. There needs to be some way to identify the last argument. This is what \; does. Note that other things may follow after the -exec switch:
find euler/ -iname "*.c*" -exec echo {} \; -or -iname "*.py" -exec echo {} \;
(This finds all c-files and python files in the euler directory.)
The reason that exec does not require the full command to be inside quotes, is that this would require escaping a lot of quotes inside the command, in most circumstances.
The string {} in find is replaced by the pathname of the current file.
The semicolon is used for terminating the shell command invoked by find utility.
It needs to be escaped, or quoted, so it won't be interpreted by the shell, because ; is one of the special characters used by shell (list operators).
See also: Why are the backslash and semicolon required with the find command's -exec option?
The (escaped) semicolon is needed so that "find" can tell where the arguments to the exec'd program end (if there are any) and additional arguments to "find" begin.
I'd recommend that you instead do that as
find . -perm 777 -print0 | xargs -0 chmod 770
"xargs" says to take the results of the find and feed it 20 at a time to the following command.

Resources