{"id":425,"date":"2014-12-09T22:04:58","date_gmt":"2014-12-09T20:04:58","guid":{"rendered":"http:\/\/www.bashpi.org\/?page_id=425"},"modified":"2021-02-04T17:32:50","modified_gmt":"2021-02-04T15:32:50","slug":"awk","status":"publish","type":"page","link":"https:\/\/www.bashpi.org\/?page_id=425","title":{"rendered":"awk"},"content":{"rendered":"<p>Awk is my favorite CLI program for parsing different input. In most cases I just use it to cut out different fields from some output as its superior to cut utility &#8211; it allows me to set custom, multi-char field separator instead of just single character in cut.<\/p>\n<h1><strong>Blocks<\/strong><\/h1>\n<p>{} &#8211; block executed once for each line of the input.<\/p>\n<p>BEGIN{} &#8211; block executed\u00a0 once at the start. useful to set some variables like custom field separator FS. You could set FS in the normal block {} also&#8230; but its faster if you don&#8217;t need to do it once for each line of the input.<\/p>\n<p>END{} &#8211; block executed once in the end. useful to print out statistics if you count something.<\/p>\n<h1><strong>Variables<\/strong><\/h1>\n<p><strong>FS<\/strong> &#8211; input field separator. default is any amount of whitespace &#8211; one or more spaces or tabs.<\/p>\n<p><strong>OFS<\/strong> &#8211; output field separator, defaults to space<\/p>\n<div>\n<div class=\"cheatsheet-shortcut-container col-xs-12\">\n<div>\n<div>\n<div class=\"cheatsheet-shortcut-container col-xs-12 is-odd\">\n<div><strong>RS<\/strong> &#8211; row or record separator. default is newline.<\/div>\n<div>\u00a0<\/div>\n<\/div>\n<div><strong>ORS<\/strong> &#8211; output record separator. set this to &#8221; &#8221; to remove newlines in the output.<\/div>\n<div class=\"cheatsheet-shortcut-container col-xs-12 is-odd\">\n<div>\u00a0<\/div>\n<div class=\"cheatsheet-keys col-xs-4\"><strong>NR<\/strong> &#8211; line\/record\u00a0 number of currently parsed input<\/div>\n<\/div>\n<\/div>\n<\/div>\n<div>\u00a0<\/div>\n<div><strong>NF<\/strong> &#8211; number of fields\/columns on current line\/record<\/div>\n<div>\u00a0<\/div>\n<div class=\"cheatsheet-keys col-xs-4\"><strong>$1,$2,$3&#8230;.$NR<\/strong>\u00a0 &#8211; references columns 1, 2, 3 up to the last one which can always referenced as<strong> $NR<\/strong> not depending on is it 10nth or 100th.<\/div>\n<div>\u00a0<\/div>\n<\/div>\n<div class=\"col-xs-1\"><strong>$0<\/strong> &#8211; references entire line\/record, all fields\/columns and separators.<\/div>\n<\/div>\n<div>\n<div class=\"cheatsheet-shortcut-container col-xs-12 is-odd\">\u00a0<\/div>\n<\/div>\n<p># awk print out last field using separator &#8220;.&#8221;<\/p>\n<pre><code># echo \"one.two.three\" <\/code><code class=\"language-bash\">|awk 'BEGIN{FS=\".\"}{print $NF;}'\nthree<\/code><\/pre>\n<p># awk print out last but one field using separator &#8220;.&#8221;. This is also useful to remove file extension from list of files.<\/p>\n<pre><code>$ echo \"one.two.three\" <\/code><code class=\"language-bash\">|awk 'BEGIN{FS=\".\"}{X=NF-1; print $X;}'\ntwo<br \/># remove file extension - quick and dirty solution. does not take into account files having zero or more than one . in the name.<br \/>\u00a3 find . -type f -printf '%f\\n' |awk 'BEGIN{FS=\".\"}{X=NF-1; print $X;}'<\/code><\/pre>\n<p># awk &#8211; print fields 1-3 only from matching line using separator &#8220;:&#8221;. Simplified version using grep below.<\/p>\n<pre><code># awk 'BEGIN{FS=\":\";}\/root\/{print $1 $2 $3;}'&lt; \/etc\/passwd\nrootx0\n# grep root \/etc\/passwd| awk 'BEGIN{FS=\":\";}{print $1 $2 $3;}'\nrootx0<\/code><\/pre>\n<p># find all unique file extensions<\/p>\n<pre><code># find \/path\/to\/files\/ -type f |awk 'BEGIN{FS=\".\";}{print $NF;}' |sort |uniq<\/code><\/pre>\n<h1>Arrays, loops, conditional expressions<\/h1>\n<p>Following example queries information about client backups from netbackup master server and parses it by using if-else statements, for-loops, arrays and array sorting<\/p>\n<p><strong>hostlist<\/strong> should have netbackup clients hostnames. For-loop just runs bpclimagelist command for each client and parses the output. Empty BEGIN blocks could be omitted but its my habbit to keep them.<\/p>\n\n\n<pre class=\"wp-block-code\"><code>for h in `cat hostlist`;do\n\n\/usr\/openv\/netbackup\/bin\/bpclimagelist -client ${h} -server netbackup.masterserver.net |awk -v hostname=\"${h}\" 'BEGIN{}{if (lastincremental == \"\" &amp;&amp; $7 == \"Incr\" &amp;&amp; $8 == \"Backup\"){lastincremental=$1;}; if (lastfull == \"\" &amp;&amp; $7 == \"Full\" &amp;&amp; $8 == \"Backup\"){lastfull=$1;}; if (lastfull != \"\" &amp;&amp; lastincremental != \"\"){exit}; }END{if (lastincremental == \"\"){lastincremental=\"n\/a\"}; if (lastfull == \"\"){lastfull=\"n\/a\"}; print hostname,\" \",lastincremental,\" \",lastfull;}' &gt;&gt; datafile.txt\n\ndone<\/code><\/pre>\n\n\n\n<p>parse that datafile.txt with another awk and produce report of missing backups.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>grep \"n\/a\" datafile.txt |awk 'BEGIN{}{if($2 == \"n\/a\" &amp;&amp; $3 == \"n\/a\" ){both&#91;bothlen++]=$1} else if($2 == \"n\/a\"){incr&#91;incrlen++]=$1} else if( $3 == \"n\/a\" ){full&#91;fulllen++]=$1};}END{if (bothlen &gt; 0){asort(both);print \"Servers without full or incremental successful backups\"; for (b = 0; b &lt; bothlen; b++){print both&#91;b];}; print \"\";}; if ( incrlen &gt; 0){ asort(incr); print \"Servers without incremental successful backups\"; for (i = 0; i &lt; incrlen; i++){print incr&#91;i];}; print \"\";}; if ( fulllen &gt; 0 ){ asort(full); print \"Servers without full successful backups\"; for (f = 0; f &lt; fulllen; f++){print full&#91;f];};}; }'<\/code><\/pre>\n\n\n\n<p>to be continued&#8230;<\/p>\n\n\n\n<p>If you found this useful, say thanks, click on some banners or <a href=\"http:\/\/www.bashpi.org\/?page_id=105\">donate<\/a>, I can always use some beer money.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Awk is my favorite CLI program for parsing different input. In most cases I just use it to cut out different fields from some output as its superior to cut utility &#8211; it allows me to set custom, multi-char field separator instead of just single character in cut. Blocks {} &#8211; block executed once for [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":397,"menu_order":0,"comment_status":"closed","ping_status":"open","template":"","meta":{"footnotes":""},"class_list":["post-425","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/www.bashpi.org\/index.php?rest_route=\/wp\/v2\/pages\/425","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.bashpi.org\/index.php?rest_route=\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/www.bashpi.org\/index.php?rest_route=\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/www.bashpi.org\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.bashpi.org\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=425"}],"version-history":[{"count":17,"href":"https:\/\/www.bashpi.org\/index.php?rest_route=\/wp\/v2\/pages\/425\/revisions"}],"predecessor-version":[{"id":1200,"href":"https:\/\/www.bashpi.org\/index.php?rest_route=\/wp\/v2\/pages\/425\/revisions\/1200"}],"up":[{"embeddable":true,"href":"https:\/\/www.bashpi.org\/index.php?rest_route=\/wp\/v2\/pages\/397"}],"wp:attachment":[{"href":"https:\/\/www.bashpi.org\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=425"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}