I'm using SSH inside a CI/CD Pipeline (so it's non-interactive), and trying to execute a couple find command (among others) to change the ownership of files and directories after executing LFTP mirror, but I keep getting this error (which makes the whole Pipeline fail):
find: missing argument to `-exec'
This is the command that uses find:
ssh -i ~/.ssh/id_rsa $USERNAME#$HOST "[other commands...]; find $SOME_PATH/ -type d -exec 'chmod 755 {} \;' && find $SOME_PATH/ -type f -exec 'chmod 644 {} \;' && echo Done"
I've already tried using escaped double quotes like so: -exec \"chmod 755 {} \;\" - but keeps throwing the same error.
What would be the main issue here?
EDIT: Solved. I removed any quotes for the -exec, removed the && and append an extra semicolon ; to each find and it works as expected.
ssh -i ~/.ssh/id_rsa $USERNAME#$HOST "[other commands...]; find $SOME_PATH/ -type d -exec chmod 755 {} \;; find $SOME_PATH/ -type f -exec chmod 644 {} \;; echo Done"
So use -exec whatever-command {} \;; [other command, echo, find, ls, whatever...].
Please check this answer for more information: https://unix.stackexchange.com/a/139800/291364
[...] When find sees that spurious exit after the -exec … ; directive, it doesn't know what to do with it; it hazards a (wrong) guess that you meant it to be a path to traverse. You need a command separator: put another ; after \; (with or without a space before). [...]
\; is processed to ; locally before the string is passed to the remote shell. You need to escape the backslash so the the ; remains escaped on the remote end.
ssh -i ~/.ssh/id_rsa $USERNAME#$HOST \
"[other commands...]; find $SOME_PATH/ -type d -exec 'chmod 755 {} \\;'
&& find $SOME_PATH/ -type f -exec 'chmod 644 {} \\;' && echo Done"
A better idea would be to use single quotes for the command argument and pass the value of $SOME_PATH as an argument to a shell.
ssh -i ~/.ssh/id_rsa $USERNAME#$HOST \
sh -c '...;
find "$1" -type d -exec chmod 755 {} \; &&
find "$1" -type f -exec chmod 644 {} \; &&
echo Done' _ "$SOME_PATH"
Note that chmod and its arguments each need to be separate arguments to the find.
In fact, you don't need to run find twice; you can provide two -exec primaries, each paired to a different -type:
ssh -i ~/.ssh/id_rsa $USERNAME#$HOST \
sh -c '...;
find "$1" \( -type d -exec chmod 755 {} \; \) -o
\( -type f -exec chmod 644 {} \; \)
&& echo Done' _ "$SOME_PATH"
Rather than the complex find commands (and associated quoting/escaping mess), you can use the built-in capabilities of chmod sympolic modes to set the permissions on files and directores differently. Specifically, the "X" permission means essentially "execute if it makes sense", which mostly means directories rather than files. The main exception is that if there's a file that already has execute set, it assumes it's intentional and keeps it. If that's ok, you can use this simpler command:
chmod -R u=rwX,go=rX "$1" # Set non-executable files to 644, executables and directories to 755
If you need to specifically clear execute bits on files, or just want to stick with find, another option take advantage of the fact that chmod accepts multiple arguments to use find ... -exec ... {} + instead of the \; version. "+" isn't a shell metacharacter, so it doesn't reqire special treatment:
find $SOME_PATH/ -type d -exec chmod 755 {} + ; find $SOME_PATH/ -type f -exec chmod 644 {} +
Related
I have the following find, sed, and grep command.
find . -type d \( -name ThirdParty -o -name 3rdParty -o -name 3rd_party \) -prune -o -type f \( -name "*.bat" \) -exec grep -L 'FOO' {} \; -print0 | xargs -0 sed -i -e '1iFOO'
I want to be able to find all .bat files in a directory that do NOT contain the string "FOO", and pipe them to a sed command that adds the string "FOO" to the top of the file. However, when i run the find and grep portion of my command (Without sed):
find . -type d \( -name ThirdParty -o -name 3rdParty -o -name 3rd_party \) -prune -o -type f \( -name "*.bat" \) -exec grep -L 'FOO' {} \; -print
it returns ALL bat files, even ones containing the string 'FOO'. This leads me to believe that the grep command is faulty. how can i fix this? thank you
Change:
grep -L 'FOO'
to:
awk '/FOO/{exit 1}'
so you only get the file name printed if FOO is not present in the file.
To be clear the whole command line would then be:
find . -type d \( -name ThirdParty -o -name 3rdParty -o -name 3rd_party \) \
-prune -o -type f \( -name "*.bat" \) \
-exec awk '/FOO/{exit 1}' {} \; -print0 |
xargs -0 sed -i -e '1iFOO'
The -exec argument to find specifies a test: if it returns 0, the result is included; if it returns nonzero, the result is excluded. grep -L returns 0 regardless of whether it finds results, so it's equivalent to -exec true \; (or not passing -exec at all).
You can achieve the desired result by passing the output from your find command into grep via xargs: find $find_args | xargs grep -L FOO.
grep is printing the names of files that do not match (with newlines rather than nulls as a terminator). You need to suppress the output of grep. Perhaps:
find . -type d \( -name ThirdParty -o -name 3rdParty -o -name 3rd_party \) \
-prune -o -type f \( -name "*.bat" \) \
-exec sh -c '! grep -q "FOO" $1' _ {} \; -print0
But it seems a bit cleaner to write:
find . -type d \( -name ThirdParty -o -name 3rdParty -o -name 3rd_party \) \
-prune -o -type f \( -name "*.bat" \) \
-not -exec grep -q "FOO" {} \; -print0
I've been having problems with multiple hidden infected PHP files which are encrypted (ClamAV can't see them) in my server.
I would like to know how can you run an SSH command that can search all the infected files and edit them.
Up until now I have located them by the file contents like this:
find /home/***/public_html/ -exec grep -l '$tnawdjmoxr' {} \;
Note: $tnawdjmoxr is a piece of the code
How do you locate and remove this code inside all PHP files in the directory /public_html/?
You can add xargs and sed:
find /home/***/public_html/ -exec grep -l '$tnawdjmoxr' {} \; | xargs -d '\n' -n 100 sed -i 's|\$tnawdjmoxr||g' --
You may also use sed immediately than using grep -but- it can alter the modification time of that file and may also give some unexpected modifications like perhaps some line endings, etc.
-d '\n' makes it sure that every argument is read line by line. It's helpful if filenames has spaces on it.
-n 100 limits the number of files that sed would process in one instance.
-- makes sed recognize filenames starting with a dash. It's also commendable that grep would have it: grep -l -e '$tnawdjmoxr' -- {} \;
File searching may be faster with grep -F.
sed -i enables inline editing.
Besides using xargs it would also be possible to use Bash:
find /home/***/public_html/ -exec grep -l '$tnawdjmoxr' {} \; | while IFS= read -r FILE; do sed -i 's|\$tnawdjmoxr||g' -- "$FILE"; done
while IFS= read -r FILE; do sed -i 's|\$tnawdjmoxr||g' -- "$FILE"; done < <(exec find /home/***/public_html/ -exec grep -l '$tnawdjmoxr' {} \;)
readarray -t FILES < <(exec find /home/***/public_html/ -exec grep -l '$tnawdjmoxr' {} \;)
sed -i 's|\$tnawdjmoxr||g' -- "${FILES[#]}"
I have a requirement to kill remote process of specific patter, pushd the path to startup and execute the script.
I tried so far with
pid=$(ssh -q username#virt ps -ef|grep $APP|grep $PORT|awk '{print $2}')
ssh -q username#virt kill -9 $pid
ssh -q username#virt "find /shared/local/path1/app -name "start_app*" -exec grep -nl "9122" {} \;| xargs -0 -I '{}' bash -c 'pushd $(dirname {});bash {};'"
When I execute above command kill processing is working fine. The final step to find for scriptfile and execute script by pushing the folder to the path is not working.
For some reason the pushd is not working fine.
The command on the local server do work fie with
find /shared/local/path1/app -name "start_app*" -exec grep -nl "9122" {} \;| xarg -0 -I '{}' bash -c 'pushd $(dirname {});bash {};'
Please help a more effective solution to accomplish this task.
You have an error in the quotes here:
ssh -q username#virt "find /shared/local/path1/app -name "start_app*" -exec grep -nl "9122" {} \;| xargs -0 -I '{}' bash -c 'pushd $(dirname {});bash {};'"
Try this in stead:
ssh -q username#virt "find /shared/local/path1/app -name 'start_app*' -exec grep -nl '9122' {} \;| xargs -0 -I '{}' bash -c 'pushd \$(dirname {});bash {};'"
As said in the title, I want the compiler to ignore pragma message for the time being, so it's easier for me to read and fix actual warnings. I've done some searching, but there doesn't seem to be any information on it.
No it isn't possible, so the best thing to do would be to mass-edit all the #pragmas out:
$ cd MySourceFolder
$ find . -name \*.m -exec perl -p -i -n -e 's/^#pragma/\/\/#pragma/' {} \;
When you want the #pragma's back again:
$ cd MySourceFolder
$ find . -name \*.m -exec perl -p -i -n -e 's/^\/\/#pragma/#pragma/' {} \;
If you do this kind of thing alot, I would wrap that in a script, and put it into your ~/bin directory.
I am trying to write a bourne-shell script that takes a string as a parameter and deletes all files in the directory containing that string
I was thinking about using find and execute rm all but I just started b-shell
find . -name $1 'core' -exec rm -i* {}\;
any help would be much appreciated. thanks.
Why not just this:
#!/bin/sh
rm *$1*
Removes files in the current directory that contain your argument.
remove.sh script:
#!/bin/sh
find . -type f -iname *$1* -exec rm -rf {} \;
usage:
$remove.sh "main"