Need help omitting folders in find command - bash

I have this line in a script I'm writing
find / \( -perm -4000 -o -perm -2000 \) -type f -exec file {} \; | grep -v ELF | cut -d":" -f1 >> $OUTPUT
It does the work, BUT I always get these messages I want to omit
find: `/proc/29527/task/29527/fd/5': No such file or directory
find: `/proc/29527/task/29527/fdinfo/5': No such file or directory
find: `/proc/29527/fd/5': No such file or directory
find: `/proc/29527/fdinfo/5': No such file or directory
How can I omit the /proc directory?

I believe this should work:
find / -path /proc -prune -o \( -perm -4000 -o -perm -2000 \) -type f ...
^^^^^^^^^^^^^^^^^^^^^ Add this to your command line

What if you redirect STDERR to /dev/null. That way, you don't see the unwanted error/warning in your TTY (STDOUT) like
{ find / \( -perm -4000 -o -perm -2000 \) -type f -exec file {} \; | grep -v ELF | cut -d":" -f1 >> $OUTPUT; } 2>/dev/null

The following prunes the proc directory:
find / -name /proc -prune -o \
\( -perm -4000 -o -perm -2000 \) -type f \
-exec file {} \; | grep -v ELF | cut -d":" -f1 >> $OUTPUT

Related

KSH88 variable inside script

I'm having trouble with KSH88
script="find . ! \( "$result" \) -mtime "$older" -xdev -type f -size +"$minsize"M -exec ls -lh {} \; | head -100 | awk '{print \$8}' | sort -rn"
files_to_delete=`$script`
When I Echo my files_to_delete variable I get :
find . ! \( -name '*.jar' -o -name '*.zip' -o -name '*.rar' -o -name '*.log' -o -name '*.xml' \) -mtime 10 -xdev -type f -size +100M -exec ls -lh {} \; | head -100 | awk '{print $8}' | sort -rn
which is what I want, when I execute it on the command line it works, but when I execute it in my KSH I get
find: bad option \(
find: [-H | -L] path-list predicate-list
Put "eval " in front of the "$script", so it becomes
files_to_delete=`eval $script`
This forces the shell to evaluate the command string.
If your shell supports it, it woudl be better to use files_to_delete=$(eval $script). The ` version is easier to miss when scanning the script quickly, and much harder to nest (commands within commands).

Find and replace with sed in directory and sub directories except few directories

I want to replace foo with bar in a directory structure but I want to skip few folders
I am using this command:
find ./ -type f -exec sed -i -e 's/foo/bar/g' {} \;
You -prune to skip directory:
find . -type f -o \
\( \( -name unwanted-dir1 -o -name unwanted-dir2 \) -prune -false \) \
-exec sed -i -e 's/foo/bar/g' {} \;
... or use -path ./path/to/your-dir instead of -name unwanted-dir if you want to match full path of the unwanted directory...
find . -type f -o \
\( \( -name unwanted-dir1 -o -name unwanted-dir2 \) -prune -false \) \
-exec sed -i -e 's/foo/bar/g' {} \;
This is not working because it's equivalent to
find . -type f -o \
\( \( -name unwanted-dir1 -o -name unwanted-dir2 \) -prune -false \) -and \
-exec sed -i -e 's/foo/bar/g' {} \;
since -and is assumed where the operator is omitted and -and has higher precedence than -o, so the -exec is never evaluated.
It works if the -type test is inside the outer parentheses:
find . \( -type f -o \
\( -name unwanted-dir1 -o -name unwanted-dir2 \) -prune -false \) \
-exec sed -i -e 's/foo/bar/g' {} \;
or, with fewer parentheses:
find . \( -name unwanted-dir1 -o -name unwanted-dir2 \) -prune -o \
-type f -exec sed -i -e 's/foo/bar/g' {} \;
or without parentheses as David C. Rankin suggested in his comment.

find: output to a file with a comment

I have a line that will generate the md5sum into a file from files included:
find / -type f \( -name "*.pl" -o -name "*.py" \) | md5sum *.pl *.py >> sum.txt
The sum.txt will output:
d41d8cd98f00b204e9800998ecf8427e file.pl
60b725f10c9c85c70d97880dfe8191b3 file.py
I would need to include the server name after the file name, preferably reading $HOSTNAME as the script will run on different servers, as:
d41d8cd98f00b204e9800998ecf8427e file.pl host.one.com
60b725f10c9c85c70d97880dfe8191b3 file.py host.one.com
The command will search through all *.pland *.py files. find will exec with md5sum command and a hostname will be added to each line. Both commands will generate same output:
find / -type f \( -name "*.pl" -o -name "*.py" \) -exec md5sum {} + | awk -v ORS=" $HOSTNAME\n" 1. >> sum.txt
find / -type f -name "*.p[ly]" -exec md5sum {} + |awk -v "h=$HOSTNAME" '{print $0,h}' >> sum.txt
An alternative would be to use find's -regex and to use sed for appending the hostname:
find / -type f -regex '.*\.\(py\|pl\)' -exec md5sum {} + | sed 's/$/ '"$HOSTNAME'/'

Recursive sed shell function doesn't do anything

Referring to other Q/As on SO, I added the following to my .bashrc:
function findandreplace {
find . -type f -name "$1" -not -path "*/.git/*" -print0 | xargs -0 sed -i 's/$2/$3/g'
}
Oddly, it doesn't do anything. When I change it to:
function findandreplace {
echo "find . -type f -name \"$1\" -not -path \"*/.git/*\" -print0 | xargs -0 sed -i 's/$2/$3/g'"
}
I get
$ findandreplace "*.cpp" "A.cpp" "B.cpp"
find . -type f -name "*.cpp" -not -path "*/.git/*" -print0 | xargs -0 sed -i 's/A.cpp/B.cpp/g'
as expected. Copy-pasting that command then performs the expected operation.
What's wrong with my initial function?
The 's/$2/$3/g' part doesn't make sense; single-quotes prevent parameter-expansion, so your actual sed script is s/$2/$3/g (dollar signs and all) rather than s/A.cpp/B.cpp/g. Since $ in a regex means "end-of-string" (or sometimes "end-of-line"), $2 will never match anything.
To fix this, you can use double-quotes instead:
function findandreplace {
find . -type f -name "$1" -not -path "*/.git/*" -print0 \
| xargs -0 sed -i "s/$2/$3/g"
}
with the caveat that this will misbehave if $2 or $3 contains slashes. (Edited to add:) To fix that, you can ask Bash to replace / with \/ in those parameters, though it's pretty ugly:
function findandreplace {
find . -type f -name "$1" -not -path "*/.git/*" -print0 \
| xargs -0 sed -i "s/${2//\//\/}/${3//\//\/}/g"
}
Because of use of single quotes:
sed -i 's/$2/$3/g'
won't work since shell won't expand these variables. Use sed like this:
sed -i "s/$2/$3/g"

sed pattern ending with a specific character or the end of line

I use grep v2.5.1 and I want to colorize the filename within the grep output.
I could use another grep command with pattern /[^/:]*\(:\|$\):
grep --color=always something */* | grep --color '/[^/:]*\(:\|$\)'
and this same pattern also works to list files:
grep --color=always something */* -l | grep --color '/[^/:]*\(:\|$\)'
But I would prefer a sed command, and I do not know how to translate \(:\|$\) in sed :-(
For instance:
echo 'dir/file: xxxx' | sed 's|/\([^/:]*\)(:|$)|/\o033[1;35m\1\o033[0m\2|'
FYI, my complete function in ~/.bashrc
gg() {
find . -name .svn -prune -o -type f '(' -name '*.java' -o -name '*.h' -o -name '*.cpp' -o -name 'Make*' -o -name '*.sh' ')' -print0 |
xargs -0 grep --color=always "$#" |
sed 's|/\([^/:]*\)(:|$)|/\o033[1;35m\1\o033[0m\2|'
}
After trying some other possibilities I finally found:
grep pattern is same as sed pattern for this purpose
And my complete function is:
gg ()
{
find . -path '*/.svn' -prune -o -type f '(' -name '*.java' -o -name '*.h' -o -name '*.hpp' -o -name '*.hxx' -o -name '*.cpp' -o -name '*.cxx' -o -name '*.c' -o -name '[Mm]akefi*[^~]' -o -name '*.sh' -o -iname '*.xml' ')' -exec grep --color=always "$#" '{}' '+' |
sed -u 's_\(/\|^\)\([^/:]*\)\(:\|$\)_\1\o033[1;37m\2\o033[0m\3_'
}
I am still open for any comments, suggestions, improvements, contributions...
cheers ;-)

Resources