Shell script to cut /proc/softirqs - shell

The following is output of "cat /proc/softirqs " :
CPU0 CPU1 CPU2 CPU3
HI: 24 13 7 54
TIMER: 344095632 253285150 121234786 108207697
NET_TX: 2366955 319 695 316044
NET_RX: 16337920 16030558 250497436 117201444
BLOCK: 19631 2747 2353 5067051
BLOCK_IOPOLL: 0 0 0 0
TASKLET: 298 93 157 20965
SCHED: 74354472 28133393 30646119 26217748
HRTIMER: 4123645358 2409060621 2466360502 401470590
RCU: 26083738 17708780 15330534 16857905
My another machine has 24 cpu cores and the output is hard to read ,
I like the output to be only cpu0 , cpu2 , cpu4 , cpu6, ....
I know cut or awk might be ued to do that ,
but no idea how to use it to get even output columns .
Edit :
awk -F" " '{printf("%10s\t%s\n", $2,$4) }'
will get
CPU1 CPU3
24 7
344095632 121234786
2366955 695
16337920 250497436
19631 2353
0 0
298 157
74354472 30646119
4123645358 2466360502
26083738 15330534
unfortunately , CPU1 should be CPU0 , CPU3 should be CPU2 ,
the first line has only 4 columns , may I skip the first line
in this shell ?!
Edit2 :
watch -d "cat /proc/softirqs | awk -F" " '{printf("%10s\t%s\n",$2,$4)}' "
encounter errors like the following :
Every 2.0s: cat /proc/softirqs | awk -F '{print }' Tue Jun 21 10:23:22 2016
Usage: awk [POSIX or GNU style options] -f progfile [--] file ...
Usage: awk [POSIX or GNU style options] [--] 'program' file ...
POSIX options: GNU long options: (standard)
-f progfile --file=progfile
-F fs --field-separator=fs
-v var=val --assign=var=val
Short options: GNU long options: (extensions)
-b --characters-as-bytes
-c --traditional
-C --copyright
-d[file] --dump-variables[=file]
-e 'program-text' --source='program-text'
-E file --exec=file
-g --gen-pot
-h --help
-L [fatal] --lint[=fatal]
-n --non-decimal-data
-N --use-lc-numeric
-O --optimize
-p[file] --profile[=file]
-P --posix
-r --re-interval
-S --sandbox
-t --lint-old
-V --version
To report bugs, see node `Bugs' in `gawk.info', which is
section `Reporting Problems and Bugs' in the printed version.
gawk is a pattern scanning and processing language.
By default it reads standard input and writes standard output.
Examples:
gawk '{ sum += $1 }; END { print sum }' file
gawk -F: '{ print $1 }' /etc/passwd
what else should I try ?!
Edit3 :
The final workable shell would like :
# define function encapsulating code; this prevents any need for extra layers of quoting
# or escaping.
run() {
awk 'NR>1{printf("%20s\t%10s\t%s\n",$1,$2,$4)}' </proc/softirqs|egrep 'TIMER|RX'
}
# export function
export -f run
# run function in subshell of watch, ensuring that that shell is bash
# (other shells may not honor exported functions)
watch -d "bash -c run"

One easy way to communicate code to a subprocess of watch that avoids escaping errors is to use an exported function:
# define function encapsulating code; this prevents any need for extra layers of quoting
# or escaping.
run() {
awk -F" " '{printf("%10s\t%s\n",$2,$4)}' </proc/softirqs
}
# export function
export -f run
# run function in subshell of watch, ensuring that that shell is bash
# (other shells may not honor exported functions)
watch "bash -c run"
To avoid the dependency on exported functions, one can also use declare -f to retrieve the function's source in an evalable form, and printf %q to escape it to survive processing by the outer shell invoked by watch:
run() {
awk -F" " '{printf("%10s\t%s\n",$2,$4)}' </proc/softirqs
}
printf -v run_str '%q' "$(declare -f run); run"
watch "bash -c $run_str"

To skip the first line, do:
awk -F" " 'NR>1{printf("%10s\t%s\n", $2,$4) }'
Why do you need -F" ", is a mystery to me. You can as well write:
awk 'NR>1{printf("%10s\t%s\n", $2,$4) }'
(As for the watch part, see other answer/s.)

Related

assign two different variables from same line and loop for every line [duplicate]

This question already has answers here:
How to read variables from file, with multiple variables per line?
(2 answers)
Closed last month.
I am trying to assign variables obtained by awk, from a 2 columned txt file.
To a command, which includes every two value as two variables in it.
For example, the file I use is;
foo.txt
10 20
33 40
65 78
my command is aiming to print ;
end=20 start=10
end=40 start=33
end=78 start=65
Basically, I want to iterate the code for every line, and for output, there will be two variables from the two columns of the input file.
I am not an awk expert (I am trying my best), what I could have done so far is this fusion;
while read -r line ; do awk '{ second_variable=$2 ; first_variable=$1 ; }' ; echo "end=$first_name start=$second_name"; done <foo.txt
but it only gives this output;
end= start=
only one time without any variable. I would appreciate any suggestion. Thank you.
In bash you only need while, read and printf:
while read -r start end
do printf 'end=%d start=%d\n' "$end" "$start"
done < foo.txt
end=20 start=10
end=40 start=33
end=78 start=65
With awk, you could do:
awk '{print "end=" $2, "start=" $1}' foo.txt
end=20 start=10
end=40 start=33
end=78 start=65
With sed you'd use regular expressions:
sed -E 's/([0-9]+) ([0-9]+)/end=\2 start=\1/' foo.txt
end=20 start=10
end=40 start=33
end=78 start=65
Just in Bash:
while read -r end start; do echo "end=$end start=$start"; done <foo.txt
What about using xargs?
xargs -n2 sh -c 'echo end=$1 start=$2' sh < file.txt
Demo
xargs -n2 sh -c 'echo end=$1 start=$2' sh <<INPUT
10 20
33 40
65 78
INPUT
Output
end=10 start=20
end=33 start=40
end=65 start=78

Syntax error when using screen with ssh and remote gawk

I need to run the following command in a bash script.
The command needs to be run inside a GNU screen so I can see the progress. So the command needs to be in quotes, but because of that I am having problems with the syntax and the code isn't running properly.
I have a file in a remote server called textfile.txt. It looks like this.
The command gawk command runs fine on its own.
test-server-name 1
test-server-name 2
test-server-name 3
...
test-server-name 23
test-server-name 24
...
I run a screen command together with an ssh command that runs a gawk command to modify a line in the text file, in this case, it should look for test-server-name-1 and add a 0 next to it like this.
test-server-name 1 0
test-server-name 2
test-server-name 3
...
test-server-name 23
test-server-name 24
...
This is what my script looks like in my local server.
localhostname='test-server-name-1'
counter=1
function='textfile'
screen -dmS $counter "ssh -i ~/.ssh/ssh-key username#masteripaddress 'gawk -i inplace -v n='0' -v s='${localhostname}-${function}' '$1 == s { $2 = n } 1' /home/master/Documents/${function}.txt';exec bash;"
But when I run it, the script runs, and I get this error in the attached screen,
gawk: cmd. line:1: ==
gawk: cmd. line:1: ^ syntax error
How do I fix it? What characters need to be escaped
(Don't do this. It'll be much easier if you put a script on remote side.)
Just give you an example (with \-style escaping):
[STEP 101] $ # to run an awk command locally
[STEP 102] $ title='THE SUM: '
[STEP 103] $ printf '%d\n' {1..10} | awk -v title="$title" '{ sum += $1 } END { print title sum }'
THE SUM: 55
[STEP 104] $
[STEP 105] $ # to run the awk command thru screen + ssh
[STEP 106] $ # added 'sleep 1' for easy watching
[STEP 107] $ title='THE SUM: '
[STEP 108] $ screen -c /dev/null -m ssh 127.0.0.1 printf\ \'%d\\n\'\ \{1..10\}\ \|\ awk\ -v\ title=\'"$title"\'\ \'\{\ sum\ +=\ \$1\ \}\ END\ \{\ print\ title\ sum\ \}\'\;\ sleep\ 1
THE SUM: 55
[screen is terminating]
[STEP 109] $

Shell Script output formatting

I have output from a shell script like below
output1 ..... 1
output2 ..... 2
output3 ............3
I tried to format it with equal spacing inside script but output still not have uniform spacing.
I want to print the output like below.
output1 ..... 1
output2 ..... 2
output3 ......3
Are there any commnads available to get this done. I use bash.
here is the code.
lnode=abc
printf "server name ......... "$lnode""
printf "\nserver uptime and load details : ......... `uptime`"
printf "\n"
lcpu=`cat /proc/cpuinfo | grep -i process |wc -l`
printf "Total number of CPUs on this server : ......... $lcpu\n"
-Thanks.
The idea of printf is that you specify a format string that specifies column widths, etc:
$ cat script.sh
lnode=abc
printf "%-40s %s\n" "server name :" "......... $lnode"
printf "%-40s %s\n" "server uptime and load details :" "......... `uptime`"
lcpu=$(cat /proc/cpuinfo | grep -i process |wc -l)
printf "%-40s %s\n" "Total number of CPUs on this server :" "......... $lcpu"
The first directive in the format string, %-40s, is applied to the first argument that follows the format string. It tells printf to display that argument in a 40-character-wide column. If we had used %40s, it would be a right-aligned column. I specified %-40s so that it would be left-aligned.
This produces output like:
$ bash script.sh
server name : ......... abc
server uptime and load details : ......... 18:05:50 up 17 days, 20 users, load average: 0.05, 0.20, 0.33
Total number of CPUs on this server : ......... 4
Documentation
Bash's printf command is similar to printf in other languages, particularly the C version. Details specific to bash are found in man bash. Detailed information about the available format options is found in man 3 printf. To begin, however, you are probably better served by a tutorial such as this one or this one or this one.

Bash error: Integer expression expected

In the sections below, you'll see the shell script I am trying to run on a UNIX machine, along with a transcript.
When I run this program, it gives the expected output but it also gives an error shown in the transcript. What could be the problem and how can I fix it?
First, the script:
#!/usr/bin/bash
while read A B C D E F
do
E=`echo $E | cut -f 1 -d "%"`
if test $# -eq 2
then
I=`echo $2`
else
I=90
fi
if test $E -ge $I
then
echo $F
fi
done
And the transcript of running it:
$ df -k | ./filter.sh -c 50
./filter.sh: line 12: test: capacity: integer expression expected
/etc/svc/volatile
/var/run
/home/ug
/home/pg
/home/staff/t
/packages/turnin
$ _
Before the line that says:
if test $E -ge $I
temporarily place the line:
echo "[$E]"
and you'll find something very much non-numeric, and that's because the output of df -k looks like this:
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/sdb1 954316620 212723892 693109608 24% /
udev 10240 0 10240 0% /dev
: :
The offending line there is the first, which will have its fifth field Use% turned into Use, which is definitely not an integer.
A quick fix may be to change your usage to something like:
df -k | sed -n '2,$p' | ./filter -c 50
or:
df -k | tail -n+2 | ./filter -c 50
Either of those extra filters (sed or tail) will print only from line 2 onwards.
If you're open to not needing a special script at all, you could probably just get away with something like:
df -k | awk -vlimit=40 '$5+0>=limit&&NR>1{print $5" "$6}'
The way it works is to only operate on lines where both:
the fifth field, converted to a number, is at least equal to the limit passed in with -v; and
the record number (line) is two or greater.
Then it simply outputs the relevant information for those matching lines.
This particular example outputs the file system and usage (as a percentage like 42%) but, if you just want the file system as per your script, just change the print to output $6 on its own: {print $6}.
Alternatively, if you do the percentage but without the %, you can use the same method I used in the conditional: {print $5+0" "$6}.

Shell scripts : Use command in awk

This is my code
awk '{a[$1":"$5]}
END{for(i in a)
{
split(i,b,":");
split(b[2],c,"[");
print b[1],b[2]
}
}' /var/log/messages
The output would be: (display Month and the Process name)
May init
May rhsmd
May kernal
I would like to change the process name to a short description.
The short description is base on the "man" document.
This command help me to print what I want.
man init | sed -n '6p' | cut -c 8-
Output:
init - Upstart process management daemon
Finally, I can't find a way to embed the "man" code to awk.
Below is what I expected final output,
How can I do that? Thank you.
May init - Upstart process management daemon
May rhsmd - A Program for querying the Red Hat Network for updates and information
May kernal
There has some sample of /var/log/messages
May 21 03:30:02 redhat rhsmd: This system is registered to RHN Classic.
Sep 22 03:35:02 redhat rhsmd: This system is registered to RHN Classic.
May 22 13:00:31 redhat init: serial (hvc0) main process (1326) killed by TERM signal
May 22 13:00:31 redhat init: tty (/dev/tty6) main process (1336) killed by TERM signal
May 22 13:00:32 redhat rhnsd[1256]: Exiting
I would use shell for this.
awk '{a[$1":"$5]}
END{for(i in a)
{
split(i,b,":");
split(b[2],c,"[");
print b[1],b[2]
}
}' /var/log/messages |
while read month cmd; do
echo -n "$month "
whatis "$cmd"
done
This awk script works for me:
update - using whatis based on tripleee's answer
#!/usr/bin/awk -f
$NF !~ /Exiting/ {
split($5, a, ":")
name = a[1]
if (!s[name]) {
"whatis " name | getline w
if (w !~ /nothing/) {
split(w,b,"- ")
s[name] = b[2]
}
else s[name] = "none"
}
printf("%s %s %s\n", $1, a[1], (s[name] != "none" ? "- " s[name] : ""))
}
This builds up a cache of the program's description from the whatis database, so each process is only looked up once. On my system whatis gives the message name: nothing appropriate if no entry exists, so check for that in the outcome. It only reports the lines that don't end in "Exiting".
Example output (note that I don't have rhsmd on my system):
May rhsmd
Sep rhsmd
May init - process control initialization
May init - process control initialization
You could try:
awk '{a[$1":"$5]}
END{
for(i in a) {
split(i,b,":");
cmd="man "b[2]" 2>/dev/null | sed -n '6p' | cut -c 8-"
cmd | getline result
print b[1],result
}
}' /var/log/messages

Resources