Running a bash find with file cp parameter error python script - bash

I'd like to copy a file_list to another location. This is being called in a python script. I have
find <sourceaddress> -exec cp '{}' <destaddress> | .* rm
but it tells me an exact parameter is missing. It runs though it gives a prompt from the command line and from the script just does nothing.

I think you are missing "\;" at the end. I am not sure what the .* rm does. Assuming you want to remove the files you can use the 'mv' command instead of 'cp'.
For copying files only from one directory to another ,
find <srcdirectory> -exec cp '{}' <destdirectory> \;
If you want to move the files, use 'mv' instead use below.
find <srcdirectory> -exec mv '{}' <destdirectory> \;

Related

"find: missing argument to -exec" when executing a shell script

I am trying to execute a shell script which has the following within it:
find /hana/shared/directory -type d -mtime +2 -exec rm -rf {} \;
This works on other SUSE Linux servers but on one. It keeps returning the following:
find: missing argument to -exec
If, however, I place the same syntax into a terminal and run it manually, it runs without issue.
I can see this is a common issue, but I believe I have tried many of the suggestions to no avail and I'm a bit stuck now.
Very carefully read find(1), proc(5), and the GNU Bash documentation.
You might want to run (this is dangerous; see below):
find / -type d mtime +2 -exec /bin/rm -f '{}' \;
(use at least -ok instead of -exec)
And you probably want to clean just your $HOME.
But you should avoid removing files from /proc/, /sys/, /dev/, /lib/, /usr/, /bin/, and /sbin/. See hier(7) and environ(7).

Using fish shell builtins with find exec

I'm trying to source a file that I can get from the output of find using these commands:
find ./ -iname activate.fish -exec source {} \;
and
find ./ -iname activate.fish -exec builtin source {} \;
But both these commands give the error of the form find: ‘source’: No such file or directory or find: ‘builtin’: No such file or directory. Seems like exec of find is not able to recognize fish's builtins ?
What I basically want to achieve is a single command that will search for Python's virtualenv activate scripts in the current directory and execute them.
So doing something like -exec fish -c 'source {}; \ would not help. I've tried it as well and it doesn't error out but does not make the changes either.
Any ideas what can be done for this ?
Thanks!
Perhaps you need:
for file in (find ./ -iname activate.fish)
source $file
end
# or
find ./ -iname activate.fish | while read file
source $file
end
Command substitution executes the command, splits on newlines, and returns that list.
As mentioned in comments, seems like -exec does not run in or affect the current shell environment. So find -exec is not gonna work for my use case.
Instead, this will work:
source (find ./ -iname activate.fish)

How to copy and rename all .yml.sample files to be .yml in Linux?

In bash I want to copy all .yml.sample files in a Git repository (recursively) and rename them to just have a .yml extension.
Eg. test.yml.sample would be copied to test.yml
Here’s as close as I’ve got, but I'm not clear on how to strip .sample off the end of the file name when I copy.
find . -depth -name "*.yml.sample" -exec sh -c 'cp "$1" "${1%/.sample/}"' _ {} \;
This should work:
find . -depth -name "*.yml.sample" -exec sh -c 'cp -p "$1" "${1%.yml.sample}.yml"' _ {} \;
The first *.yml.sample finds the files via find. Then after the -exec part, the magic happens via cp taking the results of that find via $1 and then the file extension for the copied file is set via ${1%.yml.sample}.yml where .yml.sample is the source extension, and .yml is the new destination extension.
Note I also added the -p attribute to preserve the attributes from the source file to the copied file. You might not need that, but I think it can be helpful when doing copies like this.
And—since this shell logic can be confusing—in terms of the _ {} \;, it breaks down as this:
_ {}: As explained in this answer on the Unix/Linux Stack Exchange site, “The way this works is bash takes the parameters after -c as arguments, _ {} is needed so that the contents of {} is assigned to $1 not l.”
\;: When you run find with a -exec parameter, everything that happens after that is parsed through a new shell. Meaning the main find command runs in one parent shell and stuff after -exec runs in another child shell command. If you run it as _ {} ;, the child shell command would terminate. So instead, you escape it as \; so you get _ {} \; which means only the parent sell find would interpret that ; as a “terminate” and thus the paren find command can successfully run iterative commands via -exec without stopping that child shell command. Read up on -exec command ; here.
I think you can use a tool like mmv, to mass rename all the files you need.
mmv \*.yml.sample \#1.yml
The above line should work... just make sure to test it first. Hope this helps!
Edit: If you want to copy and rename, all in one step, you can use the -c flag. That will preserve the original file, and will make a copy using the rename mask.
mmv -c \*.yml.sample \#1.yml

batch rename file extensions in subdirectories

I'm trying to create a batch file in linux that will allow me to change extensions of files in multiple subdirectories. After much searching and experimenting i've found what seems to be a solution:
find /volume1/uploads -name "*.mkv" -exec rename .mkv .avi {} +
When running the script i get the following error:
find: -exec CMD must end by ';'
I've tried adding ; and \; (with or without +) but to no avail. What's wrong with the command and how can I fix it?
Edit: Running on a Synology NAS with DSM 4.2
you have to escape all characters that would be interpreted by bash. in your case these are the semicolon and the curly braces (you forgot to escape the latter in your code):
find /volume1/uploads -name "*.mkv" -exec rename .mkv .avi \{\} \;
the {} (in our case \{\}) is expanded to the filename, so the actual call would look like rename .mkv .avi /volume1/uploads/foo/bla.mkv (which is not the exact syntax the /usr/bin/rename needs, at least on my system).
instead it would be something like:
find /volume1/uploads -name "*.mkv" -exec rename 's/\.mkv$/.avi/' \{\} \;
UPDATE
if you don't want to (or cannot) use perl's rename script, you could use the following simple bash script and save it as /tmp/rename.sh
#!/bin/sh
INFILE=$1
OUTFILE="${INFILE%.mkv}.avi"
echo "moving ${INFILE} to ${OUTFILE}"
mv "${INFILE}" "${OUTFILE}"
make it executable (chmod u+x /tmp/rename.sh) and call:
find /volume1/uploads -name "*.mkv" -exec /tmp/rename.sh \{\} \;
UPDATE2
it turned out that this question is really not about bash but about busybox.
with a limited shell interpreter like busybox, the simplest solution is just to append the new file extension:
find /volume1/uploads -name "*.mkv" -exec mv \{\} \{\}.avi \;
Not sure how different find and rename commands are on your DSM 4.2 OS so try something like:
find /volume1/uploads -name "*.mkv" | while read filename;
do mv -v "${filename}" "$(echo "${filename}" | sed -e 's/\.mkv$/\.avi/')"
done

Copy all files with a certain extension from all subdirectories

Under unix, I want to copy all files with a certain extension (all excel files) from all subdirectories to another directory. I have the following command:
cp --parents `find -name \*.xls*` /target_directory/
The problems with this command are:
It copies the directory structure as well, and I only want the files (so all files should end up in /target_directory/)
It does not copy files with spaces in the filenames (which are quite a few)
Any solutions for these problems?
--parents is copying the directory structure, so you should get rid of that.
The way you've written this, the find executes, and the output is put onto the command line such that cp can't distinguish between the spaces separating the filenames, and the spaces within the filename. It's better to do something like
$ find . -name \*.xls -exec cp {} newDir \;
in which cp is executed for each filename that find finds, and passed the filename correctly. Here's more info on this technique.
Instead of all the above, you could use zsh and simply type
$ cp **/*.xls target_directory
zsh can expand wildcards to include subdirectories and makes this sort of thing very easy.
From all of the above, I came up with this version.
This version also works for me in the mac recovery terminal.
find ./ -name '*.xsl' -exec cp -prv '{}' '/path/to/targetDir/' ';'
It will look in the current directory and recursively in all of the sub directories for files with the xsl extension. It will copy them all to the target directory.
cp flags are:
p - preserve attributes of the file
r - recursive
v - verbose (shows you whats
being copied)
I had a similar problem. I solved it using:
find dir_name '*.mp3' -exec cp -vuni '{}' "../dest_dir" ";"
The '{}' and ";" executes the copy on each file.
I also had to do this myself. I did it via the --parents argument for cp:
find SOURCEPATH -name filename*.txt -exec cp --parents {} DESTPATH \;
In 2022 the zsh solution also works in Linux Bash:
cp **/*.extension /dest/dir
works as expected.
find [SOURCEPATH] -type f -name '[PATTERN]' |
while read P; do cp --parents "$P" [DEST]; done
you may remove the --parents but there is a risk of collision if multiple files bear the same name.
On macOS Ventura 13.1, on zsh, I saw the following error when there were too many files to copy, saw the following error:
zsh: argument list too long: cp
Had to use find command along with cp to get the files copied to my destination:
find ./module/*/src -name \*.java -print | while read filelocation; do cp $filelocation mydestinationlocation; done

Resources