find . -exec echo {} \; = missing argument to `-exec' - bash

Why doesn't this work? (echo is not the real command)
$ find . -type d -exec echo {} \;
find: missing argument to `-exec'
I managed to do that anyway like this:
$ for f in `find . -type d`; do echo $f; done

This work for me.
find . -type f -exec file '{}' \;
Braces are enclosed in single quote marks to protect them from interpretation as shell script punctuation.

The following line is from the EXAMPLES section of man find:
find . -type f -exec file '{}' \;
It looks to me like the {} part needs to be in single quotes.

Related

Find and rename files by pattern works in Debian, but not in CentOS7

I need to find and rename files with question mark in names.
Example: "style.css?ver=111" should become "style.css"
I use this command
find . -type f -name "*\?*" -exec rename 's/\?.*//' '{}' \;
In Debian all works fine, but in CentOS7 I get and error that "rename: not enough arguments
"
Any ideas why?
For a reliable option that should work in any POSIX-compliant system, you may use
find . -type f -name "*\?*" -exec sh -c 'mv -- "$1" "${1%%\?*}"' findshell {} \;
$1 is the name of each file found and ${1%%\?*} is a construct that strips the substring starting from the question mark.
That should be enough if you have a few matching files. If you need it, a more efficient alternative is
find . -type f -name "*\?*" -exec sh -c '
for file in "$#"; do
mv -- "$file" "${file%%\?*}"
done
' findshell {} +

Shell using sed to remove file extension from find results

I am trying to run
find . \ -type f -name "*.sh" -exec basename {} \; | sed "s/.sh/ "
to display all files in the currenty directoy, and subdirectories, that end in .sh. I use -exec basename {} to remove the location of the file, so I just get the filenames themselves. The find command is working fine, but when i pipe it into sed "s/.sh/ " I get an error message sed: 1: "s/.sh/ ": unterminated substitute in regular expression. I am trying to replace the .sh extension with nothing, so I just get filenames.
You are only missing the close / on sed.
find . -type f -name "*.sh" -exec basename {} \; | sed "s/\.sh//"
basename can remove the extension for you.
find . -type f -name '*.sh' -exec basename {} .sh \;
Note this will work for all valid file names, not just ones that don't contain a newline.
If your basename command supports it, you can use the -s option to minimize the number of calls to basename you need.
find . -type f -name '*.sh' -exec basename -s .sh {} +
This allows multiple file names to be passed to each call to basename.

Cannot shell out to find command

In Ruby, I want to shell out the following find command:
find . -type f -name '*.c' -exec mv {} . \;
I have tried many permutations of this command:
system("find . -type f -name '*.c' -exec mv {} . \;")
`find . -type f -name '*.c' -exec mv {} . \;`
%x(find . -type f -name '*.c' -exec mv {} . \;)
But when I run the command, find generates the error message:
find: -exec: no terminating ";" or "+"
I don't think the issue is characters which need to be escaped. This is probably a really simple fix, but any help would be greatly appreciated!
You need - as #mudasobwa indicated - actually pass the backslash to the find command. If you try your string in irb, you see immediately what's going wrong:
>> "find . -type f -name '*.c' -exec mv {} . \;"
=> "find . -type f -name '*.c' -exec mv {} . ;"
However, for actually running your find command, you need to make up your mind, whether system or %x() is the right tool to use. If you want do process the stdout of the command, you have to use %x, and in this case, you have to escape the backslash, because the string is then expended as if it were a string between double quotes:
find_stdout = %x(find . -type f -name '*.c' -exec mv {} . \\;)
If you are not interested in the result, but only in the overall success (exit code,....) of the command, you shhould use system, and in this case, you could use a single quoted string, which permits you to not escape the backslashes:
result = system('find . -type f -name "*.c" -exec mv {} . \;')
Of course, escaping here is not wrong either, and some people recommend for consistency and maintainability to always escape a backslash.

find exec and strip extension from filenames

Any idea why this command is not working? btw, I'm trying to strip out the extensions of all csv files in current directory.
find -type f -iname "*.csv" -exec mv {} $(basename {} ".csv") \;
Tried many variants including the parameter expansions, xargs ... Even then all went futile.
This should do:
find ./ -type f -iname "*.csv" -exec sh -c 'mv {} $(basename {} .csv)' \;
find is able to substitute {} with its findings since the quotes prevent executing the subshell until find is done. Then it executes the -exec part.
The problem why yours is not working is that $(basename {} ".csv") is executed in a subshell (-> $()) and evaluated beforehand. If we look at the command execution step-by-step you will see what happens:
find -type f -iname "*.csv" -exec mv {} $(basename {} ".csv") \; - your command
find -type f -iname "*.csv" -exec mv {} {} \; - subshell gets evaluated ($(basename {} ".csv") returns {} since it interprets {} as a literal)
find -type f -iname "*.csv" -exec mv {} {} \; - as you see now: move does actually nothing
First, take care that you have no subdirectories; find, without extra arguments, will automatically recur into any directory below.
Simple approach: if you have a small enough number of files, just use the glob (*) operator, and take advantage of rename:
$ rename 's/.csv$//' *.csv
If you have too many files, use find, and perhaps xargs:
$ find . -maxdepth 1 -type f -name "*.csv" | xargs rename 's/.csv$//'
If you want to be really safe, tell find and xargs to delimit with null-bytes, so that you don't have weird filenames (e.g., with spaces or newlines) mess up the process:
$ find . -maxdepth 1 -type f -name "*.csv" -print0 | xargs -0 rename 's/.csv$//'

Using find(1) in command substitution and quote filenames with blanks

I'd like to use find inside a command substitution, where the returned filenames contain whitespace. What option do I need so it correctly quotes the filenames? I tried -print0, but it will not work in the shell itself.
example:
command $(find . -type f) some other params
I also tried with -exec echo "{}" \;, but that was of no help either.
If I use set -x to display shell expansion and the actual command which is executed I get:
$ command `find -type f -printf \"%p\"\ ` some other params
++ find -type f -printf '"%p" '
+ command '"./file_with' 'blanks"' '"./another' 'file"' some other params
Where are the single quotation marks coming from and why are they applied to each "word"?
Put the find result in an array, and run command "${array[#]}" some other params.
Maybe the printf action is more amenable to being contained in a substitution (GNU find only, though):
command $(find . -type f -printf \"%P\"\ ) some other params
The %P placeholder is the filename minus the argument to find, so in cases other than find ., you'd probably want %p instead.
find /what/ever -name "what ever" -exec echo "\{\}" \;
works here (Ubuntu 10.04 default gterm with bash)
Just tried
find /bin -name ls -exec \{\} -lah \;
`find /bin -name ls -exec echo \{\} \;` -lah
MYCMD=`find /bin -name ls -exec echo \{\} \;` && $MYCMD -lah
MYCMD=$(`find /bin -name ls -exec echo \{\} \;` -lah) && echo $MYCMD
MYCMD=$(`find /bin -name ls` -lah) && echo $MYCMD
all work as expected

Resources