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

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 ;-)

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).

How to combine these 2 commands into single line command

I have 2 useful bash command below, but i want to combine it together.
Is it possible to do ?
find "$1" -type f -print0 | xargs -0 sha1sum -b
find "$1" -type f ! -iname '*thumbs.db*' -print0 | xargs -0 stat -c "%y %s %n"
If you want to write it in one line, you can just use "&" to combine the commands. Maybe this is what you meant:
find "$1" -type f -print0 | xargs -0 sha1sum -b & find "$1" -type f ! -iname '*thumbs.db*' -print0 | xargs -0 stat -c "%y %s %n"

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'/'

Need help omitting folders in find command

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

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"

Resources