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

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.

Related

What is good way to move a directory and then run a command to the file inside it using a bash shell one-liner

I would like to find txt files with find command and move the directory of the found file, and then apply a command to the file using a bash shell one-liner
For example, this command works, but the acmd is executed in the current directory.
$ find . -name "*.txt" | xargs acmd
I would like to run acmd in the txt file's direcotry.
Does anyone have good idea?
From the find man page:--
-execdir command ;
-execdir command {} +
Like -exec, but the specified command is run from the subdirec‐
tory containing the matched file, which is not normally the
directory in which you started find. This a much more secure
method for invoking commands, as it avoids race conditions dur‐
ing resolution of the paths to the matched files. As with the
-exec action, the `+' form of -execdir will build a command line
to process more than one matched file, but any given invocation
of command will only list files that exist in the same subdirec‐
tory. If you use this option, you must ensure that your $PATH
environment variable does not reference `.'; otherwise, an
attacker can run any commands they like by leaving an appropri‐
ately-named file in a directory in which you will run -execdir.
The same applies to having entries in $PATH which are empty or
which are not absolute directory names. If find encounters an
error, this can sometimes cause an immediate exit, so some pend‐
ing commands may not be run at all. The result of the action
depends on whether the + or the ; variant is being used;
-execdir command {} + always returns true, while -execdir com‐
mand {} ; returns true only if command returns 0.
Just for completeness, the other option would be to do:
$ find . -name \*.txt | xargs -i sh -c 'echo "for file $(basename {}), the directory is $(dirname '{}')"'
for file schedutil.txt, the directory is ./Documentation/scheduler
for file devices.txt, the directory is ./Documentation/admin-guide
for file kernel-parameters.txt, the directory is ./Documentation/admin-guide
for file gdbmacros.txt, the directory is ./Documentation/admin-guide/kdump
...
i.e. have xargs "defer to a shell". In usecases where -execdir suffices, go for it.

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.

Use find exec with sed to replace part of file name and copy it

I have some settings file which need to go to appropriate location.
eg. settings.location1, settings.location2, settings.location3 which need to go to the appropriate folders namely location1, location2 and location3 and be renamed as simple settings.
eg.
/some/path/settings.location1 -> /other/path/location1/settings
/some/path/settings.location2 -> /other/path/location2/settings
I came up with the following comand:
find /some/path/settings.* -exec cp {} /other/path/$(echo {} | sed 's/.*\.//')/settings \;
But for some reason the sed does not get executed. And the result is
cp: cannot create regular file `/other/path//some/path/settings.location1/settings': No such file or director
It seems that if I run them separately all commands get executed well, but not if I put in exec. What am I doing wrong?
to make this work you need to create the intermediate folder when they are not present in the file system.
You can try:
find /some/path/settings.* -exec mkdir -p /other/path/$(ls -m1 {})/ && cp {} /other/path/$(ls -m1 {})/settings \;
I solved this by writing a very simple shell script which modified its parameters and did the operation, then having find do an exec on that script, passing {} multiple times.
In terms of your action, I think it would be something like:
find /some/path/settings.* -exec /bin/bash -c 'cp "$0" \
/other/path/"${1:s^/some/path/settings.^^}"/settings' {} {} \;
N.B. I inserted a line break after "$1" for ease of reading, but this should all be on one line. And I added double quotes around paths in case there are spaces in your paths. You might not need that precaution.
The Bash man page says,
-c If the -c option is present, then commands are read from the first non-option argument command_string. If there are arguments after the command_string, the first argument is assigned to $0 and any remaining arguments are assigned to the positional parameters. The assignment to $0 sets the name of the shell, which is used in warning and error messages.
The contents of the -exec script are: the bash interpreter path, the -c option, a quoted argument, find's path {}, then find's path {} again.
The quoted argument contains the shell script. Bash sets the next two arguments to $0 and $1, then runs the shell script. The script uses history substitution ${1:s^/some/path/settings.^^} to modify the path from find to keep only the part you need.

find: missing argument to `-exec' with -exec scp {}

I wrote a script which will login to Prod server and find a file and copy that to StandBy server.
My script is:
# ! /bin/ksh
ssh -l oracle -p 20022 IP_Address "find /opt/oracle/wcm/backup/export/ -name "*.DMP" -mtime -1 -exec scp {} oracle#IP_Address:/opt/oracle/wcm/impdumps"
After running the script I am getting:
find: missing argument to `-exec'
I looked all the document saying put '{}' or \; at the end of line, but nothing works. What am I doing wrong?
You need to end the -exec with an escaped command separator. From the manual:
-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.
What you're doing should work; you suggested you'd tried to put '\; at the end of line', but it's not clear if you did it at the end of the whole combined command string:
ssh ... "find ..." \;
which wouldn't work and would still give the 'missing argument' error; or at the end of the find command, i.e. within the quoted command you're passing as an argument to ssh:
ssh ... "find ... \;"
You also have two potential layers of shell expansion. The \; will be expanded by your local shell, so the remote shell can see it as just ;. You might need to escape it twice, I think, though it works for me either way.
You should also escape the quotes around your filename pattern.
ssh -l oracle -p 20022 IP_Address "find /opt/oracle/wcm/backup/export/ -name \"*.DMP\" -mtime -1 -exec scp {} oracle#IP_Address:/opt/oracle/wcm/impdumps \\;"
You might find it simpler to run this command directly on your prod server rather than remotely, but I have no idea why you're choosing to do that; or to run rsync locally on your prod server if you're doing this regularly. If you stick with find you should note the warning in the manual about the security problems, and consider using -execdir.

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.

Resources