Often I need to analyze large logs in console.
I use the following command to colorize important keywords:
echo "string1\nerror\nsuccess\nstring2\nfail" | perl -p -e 's/(success)/\e[1;32;10m$&\e[0m/g;' -e 's/(error|fail)/\e[0;31;10m$&\e[0m/g'
It will colorize "success" with green, and error messages with red and keeps others lines unchanged (as they contain some useful info).
But in some cases I need to colorize values after some marker, but not marker itself, i.e. in these lines
Marker1: value1
Marker2: value2
need to highlight only value1 and value2 by known markers.
I'm looking for a way to modify my current oneliner to add this function
Also I tried the following solution, which I like less
#!/bin/bash
default=$(tput op)
red=$(tput setaf 1 || tput AF 1)
green=$(tput setaf 2 || tput AF 2)
sed -u -r "s/(Marker1: )(.+)$/\1${red}\2${default}/
s/(Marker2: )(.+)$/\1${green}\2${default}/" "${#}"`
But it has some problem with buffering, so it's ok for some constant file, but log which is continuosly running is not displayed at all
UPDATE:
Found a solution with help of some perl guru.
echo -e "string1\nerror\nsuccess\nstring2\nfail\nMaker1: value1\nMaker2: value2" | \
perl -p \
-e 's/(success)/\e[32m$&\e[0m/g;' \
-e 's/(error|fail)/\e[31m$&\e[0m/g;' \
-e 's/(Maker1:) (.*)/$1 \e[36m$2\e[0m/m;' \
-e 's/(Maker2:) (.*)/$1 \e[01;34m$2\e[0m/m;'
echo -e "string1\nerror\nsuccess\nstring2\nfail\nMaker1: value1\nMaker2: value2" | \
perl -p \
-e 's/(success)/\e[32m$&\e[0m/g;' \
-e 's/(error|fail)/\e[31m$&\e[0m/g;' \
-e 's/(Maker1:) (.*)/$1 \e[36m$2\e[0m/m;' \
-e 's/(Maker2:) (.*)/$1 \e[01;34m$2\e[0m/m;'
#!/bin/bash
default=$(tput op)
red=$(tput setaf 1 || tput AF 1)
green=$(tput setaf 2 || tput AF 2)
#default='e[0m'
#red='e[0;31;10m'
#green='e[1;32;10m'
# automaticaly use passed argument file if any or stdin if not
sed -u -r \
"/success/ s//${green}&${default}/
/error|fail/ s//${red}&${default}/
/^Marker1:/ {s//\1${red}/;s/$/${default}/;}
/^Marker2:/ {s//\1${green}/;s/$/${default}/;}" \
$( [ ${##} -gt 0 ] && echo ${#} )
For a one line:
remove other line thans sed one
replace newline in sed by ;
use directly the terminal code in place of variable
remove the last line if you pipe or use specific file instead
Related
i have a file.txt with contents
2021-12-03;12.20.31;13;00000.00;00000.00;NO LINK
2021-12-03;12.33.31;15;00199.94;00000.00;Status OK
2021-12-03;12.35.33; 2;01962.33;00015.48;;Status OK
2021-12-03;13.05.31;13;00000.00;00000.00;NO LINK
so what command to output like below
2021-12-03;12:20:31;13;00000.00;00000.00;NO LINK
2021-12-03;12:33:31;15;00199.94;00000.00;Status OK
2021-12-03;12:35:33; 2;01962.33;00015.48;Status OK
2021-12-03;13:05:31;13;00000.00;00000.00;NO LINK
note.
cut -b 12-19 file.txt (is time)
Thanks for your help.
Rido
I assumed that the lines you want to modify are contained in a file (which I called filea.txt). The script should solve your problem.
Contents of the file 'filea.txt':
$> cat filea.txt
2021-12-03;12.20.31;13;00000.00;00000.00;NO LINK
2021-12-03;12.33.31;15;00199.94;00000.00;Status OK
2021-12-03;12.35.33; 2;01962.33;00015.48;;Status OK
2021-12-03;13.05.31;13;00000.00;00000.00;NO LINK
Script File:
$> cat refrm
#!/usr/bin/bash
in_file="filea.txt"
while read -r line || [ -n "$line" ];
do
line=$(echo "${line}" | sed -E 's/;{2,}/;/g')
IFS=$'\n'
line=$(echo ${line} | sed 's/;/\n/g')
arr=($(IFS='\n' ; echo "${line}"))
for ((n=0; n < ${#arr[*]}; n++))
do
if [[ ${arr[n]} =~ ^[0-9]{2}\.[0-9]{2}\.[0-9]{2} ]];
then
arr[n]=`echo ${arr[n]} | sed 's/\./:/g'`
fi
done
nline=$(IFS=";" ; echo "${arr[*]}")
echo "${nline}"
done < ${in_file}
Output:
$> refrm
2021-12-03;12:20:31;13;00000.00;00000.00;NO LINK
2021-12-03;12:33:31;15;00199.94;00000.00;Status OK
2021-12-03;12:35:33; 2;01962.33;00015.48;Status OK
2021-12-03;13:05:31;13;00000.00;00000.00;NO LINK
I have tried the below Perl command to find a $from_word variable and replace it with $to_word variable in the $bat_file_path file.
system("perl -i -p -e 's/$from_word/$to_word/ee' $bat_file_path");
but I get error as
Substitution replacement not terminated at -e line 4.
Also it did not replaced as expected.
Please help me out of this concern.
sub change_cg_name {
if(!-e $output_running) {
print ("show running file not available. test case failed. [$output_running]");
return 0;
}
if(!-e $bat_file_path) {
print ("bat file not available test case filed. [$bat_file_path]");
return 0
}
my $from_word=`grep 'config-group type node IMPT_' $bat_file_path | awk '{print \$(4)}'`;
my $to_word= `grep 'config-group type node IMPT_' $output_running | awk '{print \$(4)}'`;
print("from WORD IS [$from_word]");
print("TO WORD IS [$to_word]");
if($to_word ne "") {
if (index($to_word, "IMPT_") != -1) {
system("perl -i -p -e 's/"$from_word"/"$to_word"/ee' $bat_file_path");
system("perl -p -i -e 's/\r\n$/\n/g' $bat_file_path");
print("ARUL changed the impt name in the bat file [$to_word] and file [$bat_file_path]");
return 0;
}
}
}
Change this line:
system("perl -i -p -e 's/"$from_word"/"$to_word"/ee' $bat_file_path");
with
system("perl -i -p -e 's/$from_word/$to_word/ee' $bat_file_path");
serenesat is right in removing the incorrectly nested quotation marks.
glenn jackman is right in pointing to the line endings in the $from_word and $to_word values. Instead of removing them, I suggest not to produce them in the first place by changing the awk command print \$(4) to printf "%s", \$(4).
Finally, in the command system("perl -p -i -e 's/\r\n$/\n/g' $bat_file_path") the \n and $ need \-escaping: system("perl -p -i -e 's/\r\\n\$/\\n/g' $bat_file_path").
I have gotten myself into Makefile-hell :(
I have a file test.par containing values:
$ABC=123 ! some comment
$DEF=456 ! comment
and I have a template source file (actually in fortran, but that does not make a difference here) test/template.c:
int main(void) {
return $ABC+$DEF ;
}
and I want to set the values in the code, like a preprocessor would do. So I wrote a target in my Makefile like so:
default:
for f in test/*; do \
while read l ; do \
key="$$(echo $$l | cut -d "=" -f 1 | tr -d ' ')";\
val=$$(echo $$l | cut -d "=" -f 2 | cut -d " " -f 1);\
[[ -z "$$val" ]] && \
val=$$(echo $$l | cut -d "=" -f 2 | cut -d " " -f 2);\
echo $$key $$val;\
cp $$f $$f.out ;\
sed -i "s/$$key/$$val/g" $$f.out;\
done < test.par;\
done;
I go through every file in test/ (there are many) in the for loop and "apply" every line in test.par in the while loop.
The expected result is
int main(void) {
return 123+456 ;
}
What I get is
int main(void) {
return $ABC+456 ;
}
And now it is getting crazy: If I switch the to lines in the test.par file, I get:
int main(void) {
return 123+$DEF ;
}
If there are more lines, there no substitution at all.
What is wrong with me!!!???!!!
edit: I cannot make too many changes to the original code, so aI was hoping to solve this in the Makefile.
You keep reusing the original file for substitutions, so only the last one actually sticks (the result of all substitutions but the last is overwritten by the next). After
sed "s/$$key/$$val/g" $$f > $$f.out;\
put
cp "$$f.out" "$$f";\
to fix this. (Or make a working copy of $$f, if you want $$f unchanged, e.g., cp "$$f" "$$f.out" before the loop and use sed -i "s/$$key/$$val/g" "$$f.out" inside.)
I'm trying to port a GNU sed command to BSD sed (in OSX). The command is:
cat -- "$1" | sed -n -e "\${/^#/H;x;/${tapPrintTapOutputSedPattern}/p;}" \
-e "/${tapPrintTapOutputSedPattern}/{x;/${tapPrintTapOutputSedPattern}/p;b;}" \
-e "/^#/{H;b;}" \
-e "x;/${tapPrintTapOutputSedPattern}/p" \
-e "/^Bail out!/q"
It works on GNU sed, but BSD sed gives this error:
sed: 2: "/^Bail out!/q
": unexpected EOF (pending }'s)
This is the command after the variable expansions, in case it's relevant:
cat -- "test021.tap" | sed -n \
-e "\${/^#/H;x;/^not ok\|^ok \([0-9]\+ \)\?# [tT][oO][dD][oO]\|^Bail out!/p;}" \
-e "/^not ok\|^ok \([0-9]\+ \)\?# [tT][oO][dD][oO]\|^Bail out!/{x;/^not ok\|^ok \([0-9]\+ \)\?# [tT][oO][dD][oO]\|^Bail out!/p;b;}" \
-e "/^#/{H;b;}" \
-e "x;/^not ok\|^ok \([0-9]\+ \)\?# [tT][oO][dD][oO]\|^Bail out!/p" \
-e "/^Bail out!/q"
Any ideas about why/how to fix it?
Cheers!
Try using newlines instead of a semicolons, at least before the branch commands (b) in the statements. See if this works:
sed -n "
\${
/^#/H
x
/${tapPrintTapOutputSedPattern}/p
}
/${tapPrintTapOutputSedPattern}/{
x
/${tapPrintTapOutputSedPattern}/p
b
}
/^#/{
H
b
}
x
/${tapPrintTapOutputSedPattern}/p
/^Bail out!/q
" "$1"
I have a file which looks like below:
memory=500G
brand=HP
color=black
battery=5 hours
For every line, I want to remove everything after = and also the =.
Eventually, I want to get something like:
memory:brand:color:battery:
(All on one line with colons after every word)
Is there a one-line sed command that I can use?
sed -e ':a;N;$!ba;s/=.\+\n\?/:/mg' /my/file
Adapted from this fine answer.
To be frank, however, I'd find something like this more readable:
cut -d = -f 1 /my/file | tr \\n :
Here's one way using GNU awk:
awk -F= '{ printf "%s:", $1 } END { printf "\n" }' file.txt
Result:
memory:brand:color:battery:
If you don't want a colon after the last word, you can use GNU sed like this:
sed -n 's/=.*//; H; $ { g; s/\n//; s/\n/:/g; p }' file.txt
Result:
memory:brand:color:battery
This might work for you (GNU sed):
sed -i ':a;$!N;s/=[^\n]*\n\?/:/;ta' file
perl -F= -ane '{print $F[0].":"}' your_file
tested below:
> cat temp
abc=def,100,200,dasdas
dasd=dsfsf,2312,123,
adasa=sdffs,1312,1231212,adsdasdasd
qeweqw=das,13123,13,asdadasds
dsadsaa=asdd,12312,123
> perl -F= -ane '{print $F[0].":"}' temp
abc:dasd:adasa:qeweqw:dsadsaa:
My command is
First step:
sed 's/([a-z]+)(\=.*)/\1:/g' Filename |cat >a
cat a
memory:
brand:
color:
battery:
Second step:
sed -e 'N;s/\n//' a | sed -e 'N;s/\n//'
My output is
memory:brand:color:battery: