Linux Grep Probably Simple Answer - linux

I am working with the zone.tab under /usr/share/zoneinfo/zonetab and I am having trouble displaying the data in a certain format.
the command I run:
cat zone.tab | awk '!/#/ {print $3}' | sort
this returns a list of regions and contries:
America/Washington
Pacific/Enderbury
What I need is for the above to return everything after the last / on each line.
There are some cases such as Pacific/Somewhere/A. I have a regex ([^/]+$) that should work but it doesn't. Any ideas?

You can also do it all in a single awk command:
awk '!/^#/ { sub(".*/", "", $3); print $3 }' /usr/share/zoneinfo/zone.tab
---- ----------------- --------
| | |
for non-comment lines | |
| |
modify 3rd col |
leaving only text |
after last slash |
|
Then print modified 3rd col

Pipe the output to sed -e 's;^.*/;;'. For example,
echo -e "America/Washington\nPacific/Enderbury" | sed 's;^.*/;;'

sed s:.*/:: /usr/share/zoneinfo/zone.tab

awk '!/^#/ { print $3;} ' < /usr/share/zoneinfo/zone.tab | awk -F/ ' { print $NF; }'

This regex might work:
# echo -e "a\n\a/b\na/b/c\na/b/c/d\n" |sed 's#^\(\([^/]*/\)*\)\(.*\)#\3#'
a
b
c
d
Perhaps sed -r 's#^(([^/]*/)*)(.*)#\3#' which removes the tangle of backslashes is clearer.

Related

Strip a part of string in linux

Apps-10.00.00R000-B1111_vm-1.0.3-x86_64.qcow2 is my string and the result I want is vm-1.0.3
What is the best way to do this
Below is what I tried
$ echo Apps-10.00.00R000-B1111_vm-1.0.3-x86_64.qcow2 | awk -F _ {'print $2'} | awk -F - {'print $1,$2'}
vm 1.0.3
I also tried
$ echo Apps-10.00.00R000-B1111_vm-1.0.3-x86_64.qcow2 | awk -F _ {'print $2'} | awk -F - {'print $1"-",$2'}
vm- 1.0.3
Here I do not need space in between
I tried using cut and I got the expected result
$ echo Apps-10.00.00R000-B1111_vm-1.0.3-x86_64.qcow2 | awk -F _ {'print $2'} | cut -c 1-8
vm-1.0.3
What is the best way to do the same?
Making assumptions from the 1 example you provided about what the general form of your input will be so it can handle that robustly, using any sed:
$ echo 'Apps-10.00.00R000-B1111_vm-1.0.3-x86_64.qcow2' |
sed 's/^[^-]*-[^-]*-[^_]*_\(.*\)-[^-]*$/\1/'
vm-1.0.3
or any awk:
$ echo 'Apps-10.00.00R000-B1111_vm-1.0.3-x86_64.qcow2' |
awk 'sub(/^[^-]+-[^-]+-[^_]+_/,"") && sub(/-[^-]+$/,"")'
vm-1.0.3
You don't need 2 calls to awk, but your syntax with the single quotes outside the curly's, including printing the hyphen:
echo Apps-10.00.00R000-B1111_vm-1.0.3-x86_64.qcow2 |
awk -F_ '{print $2}' | awk -F- '{print $1 "-" $2}'
If your string has the same format, let the field separator be either - or _
echo Apps-10.00.00R000-B1111_vm-1.0.3-x86_64.qcow2 | awk -F"[-_]" '{print $4 "-" $5}'
Or split the second field on - and print the first 2 parts
echo Apps-10.00.00R000-B1111_vm-1.0.3-x86_64.qcow2 | awk -F_ '{
split($2,a,"-")
print a[1] "-" a[2]
}'
Or with gnu-awk a bit more specific match with a capture group:
echo Apps-10.00.00R000-B1111_vm-1.0.3-x86_64.qcow2 |
awk 'match($0, /^Apps-[^_]*_(vm-[0-9]+\.[0-9]+\.[0-9]+)/, a) {print a[1]}'
Output
vm-1.0.3
This is the easiest I can think of:
echo "Apps-10.00.00R000-B1111_vm-1.0.3-x86_64.qcow2" | cut -c 25-32
Obviously you need to be sure about the location of your characters. In top of that, you seem to be have two separators: '_' and '-', while both characters also are part of the name of your entry.
echo 'Apps-10.00.00R000-B1111_vm-1.0.3-x86_64.qcow2' | sed -E 's/^.*_vm-([0-9]+).([0-9]+).([0-9]+)-.*/vm-\1.\2.\3/'

Arithmetic in Shell script

After executing this
ta=`zcat abc.log.2019071814.gz |grep "R_MT"|grep "A:1234"|grep "ID:413"|awk -F"|" '{print $20}'|sort|uniq -c|awk '{$1=$1};1'`
Here $20 indicates the "S:" entry in each row (I am taking the unique count of all s values),I am getting result as
93070 S:1 11666 S:8 230 S:9
so what I need is the sum of all occurrence of s values .i.e 93070+11666+230
so result be total=104966
$ echo 93070 S:1 11666 S:8 230 S:9 | sed -E 's,S:[0-9]+,,g' | sed 's, ,+,g' | bc -
104966
Append to your last awk:
| awk '{sum+=$1} END {print sum}'
or use this (awk ignores columns with S:1, S:8 and S:9):
echo $ta | awk '{for(i=1;i<=NF;i++) t+=$i; print t; t=0}'
or use every second column:
echo $ta | awk '{for(i=1;i<=NF;i=i+2) t+=$i; print t; t=0}'
I won't help you all the way, but know that you can use bc to perform arithmetic.
echo "93070 + 11666 + 230" | bc
would give you:
104966

Use result of pipeline as argument for another command

I'm trying to make part of the output of the first command as another command's argument.
Output of first command is like this, and 3000 is what I want:
XXXXXXXXXXXXX
abcdefg 1020 10:30
[1000] 3000
I extract the pattern by ./command1 | grep '^\[' | awk 'print $2', so it will print out 3000, the value I want.
I'd like to make 3000 as an argument of command2 ./command2 3000. How do I make this work?
command2 $( command1 | awk '/\[/{ print $2 }' )
You can use xargs to pass the input to a new command. In your example you need to include curly braces in your awk argument as well.
./command1 | grep '^\[' | awk '{ print $2 } ' | xargs ./command2
Or more concisely
.command1 | awk '/^\[/ { print $2 }' | xargs ./command2
Example:
echo "[1000] 3000" | awk '/^\[/ { print $2 }' | xargs echo
Output:
3000
There's also sed:
./command1 | sed -n 'n;n;p' | awk '{print $2}'
All together now:
./command2 $(./command1 | sed -n 'n;n;p' | awk '{print $2}') # ./command2 3000
sed will skip 2 lines and print the third.
I would personally try backticks first:
./command2 `./command1 | grep '^\[' | awk 'print $2'`

How can I 'pad out' a CSV file in bash?

For example suppose I wish for a CSV file with 5 columns. How could I convert
a,b,c,d
d,e,f
into
a,b,c,d,
d,e,f,,
Easy in Awk:
awk -F, -vOFS=, '{$5=$5}1'
Not too hard in Bash:
IFS=,
while read -a F; do
for ((i=0; i<5; i++)); do
F[i]=${F[i]}
done
echo "${F[*]}"
done
Example with awk:
$ awk -F, '{printf("%s,%s,%s,%s,%s\n",$1,$2,$3,$4,$5)}' example.txt
a,b,c,d,
d,e,f,,
or
$ awk -F, -v OFS=, '{print $1,$2,$3,$4,$5}' example.txt
I found a solution with GNU sed:
sed -r 's/^([^,]*)(,|)([^,]*)(,|)([^,]*)(,|)([^,]*)(,|)$/\1,\3,\5,\7,/'
# | | | | ^ ^ ^ ^
# | | | | | | | |
# |__________|__________|__________|__________| | | |
# |__________|__________|_____________| | |
# |__________|________________| |
# |___________________|
Proof:
echo -e "a,b,c,d\nd,e,f\nx" | sed -r 's/^([^,]*)(,|)([^,]*)(,|)([^,]*)(,|)([^,]*)(,|)$/\1,\3,\5,\7,/'
a,b,c,d,
d,e,f,,
x,,,,
Another approach which I like very much is this:
gawk '{print $0 ",,,,,"}' a | cut -d \, -f 1-5
I think it is much more simple and clear

perl linux command not working

cat t.incopt.02.20110221 | awk -F, '{print $1}' | sort | uniq
got unque records
but if i inserted into perl,
#FETCH_REQ_DETAILS = `cat t.incopt.02.20110221 | awk -F\, '{print $1}' \| sort \| uniq`;
if i print the above array vari, i getting entire file content, i guess the linux command not working correctly when i use inside perl,
I think you just need to enclose the command in back tick and escape only the $
#FETCH_REQ_DETAILS = `cat t.incopt.02.20110221 | awk -F, '{print \$1}' | sort | uniq;`
Try the following:
my $cmd='cat t.incopt.02.20110221 | awk -F, \'{print $1}\' | sort | uniq';
#FETCH_REQ_DETAILS = `$cmd`;

Resources