Date: Mon, 5 Oct 2015 06:34:05 +0200 From: Polytropon <freebsd@edvax.de> To: "William A. Mahaffey III" <wam@hiwaay.net> Cc: FreeBSD Questions !!!! <freebsd-questions@freebsd.org> Subject: Re: awk question Message-ID: <20151005063405.e0a6030c.freebsd@edvax.de> In-Reply-To: <5611F776.9090701@hiwaay.net> References: <5611C922.4050007@hiwaay.net> <20151005042129.1f153ec6.freebsd@edvax.de> <5611F776.9090701@hiwaay.net>
next in thread | previous in thread | raw e-mail | index | archive | help
On Sun, 4 Oct 2015 23:12:48 -0453.75, William A. Mahaffey III wrote: > On 10/04/15 21:27, Polytropon wrote: > > On Sun, 4 Oct 2015 19:55:08 -0453.75, William A. Mahaffey III wrote: > >> I am using awk & smartctl in a small shell script to print out HDD temps > >> in a purty format, 1 line per drive. As it happens, the output I want is > >> spread out over 4 lines of smartctl out, requiring (I *think*) 4 calls > >> to smartctl each piped to its own awk invocation to pull out the line I > >> want & print its info out. Is there some way to get awk to consider more > >> than 1 line at a time ? In my case my 4 lines are indeed sequential, & > >> it would be a bit more efficient if I could process all 4 lines once I > >> found the 1st one. This is definitely *not* critical, what I have now > >> works AOK, I was/am just curious if it could be optimized a bit. TIA & > >> have a good one. > > I'm not sure I understand your question correctly, as you're not > > providing some example input data and what output you want. But > > awk can process one line against multiple patterns, and if, let's > > say, 4 patterns match, 4 lines will be output: > > > > smartctl <params> | awk ' > > /pattern1/ > > /pattern2/ > > /pattern3/ > > /pattern4/ > > ' > out.txt > > > > If no action is provided, the whole line will be printed; if you > > just want some (maybe postprocessed) fields of a line, add > > > > { print <whatever } > > > > to each pattern. Another way is "counting down" the amount of > > additional lines after one pattern has been found: > > > > smartctl <params> | awk ' > > { > > if (nextlines > 0) { > > print; > > nextlines--; > > } > > } > > /pattern/ { > > nextlines = 4; > > } > > ' > out.txt > > > > The first block without a pattern will always be executed > > (in this case, "print" is the command that will be called > > for all desired lines), and the one with a pattern that > > will "trigger" that first block to actually output something. > > > > > > > > By the way: If there is no processing, and you just need some > > data lines as is, why not use grep? > > > > smartctl <params> | grep "<pattern>" -A 4 > out.txt > > > > See "man grep" for details on the -A option. > > > Good point, here is the relevant part of the smartctl output: > > [root@kabini1, /etc, 7:10:34pm] 915 % smartctl -l scttemp /dev/ada0 > smartctl 6.4 2015-06-04 r4109 [FreeBSD 9.3-RELEASE-p24 amd64] (local build) > Copyright (C) 2002-15, Bruce Allen, Christian Franke, www.smartmontools.org > > === START OF READ SMART DATA SECTION === > SCT Status Version: 3 > SCT Version (vendor specific): 256 (0x0100) > SCT Support Level: 1 > Device State: Active (0) > Current Temperature: 27 Celsius > Power Cycle Min/Max Temperature: 23/31 Celsius > Lifetime Min/Max Temperature: 19/33 Celsius > Lifetime Average Temperature: 23 Celsius > Under/Over Temperature Limit Count: 0/0 > > I am invoking smartctl 4 times per drive to extract & process (print in > my own format) the 4 lines beginning w/ 'Current Temperature:'. I want > the resulting output in 1 line per drive as such (for 4 drives): > > [root@kabini1, /etc, 7:32:53pm] 456 % hddtemp /dev/ada[0-3] > SMART supported, SMART enabled > drive /dev/ada0: HGST HTS721010A9E630, S/N: JR10006PGYH08E, Temp. 27 > degC, min/max, cycle: 23/31, lifetime: 19/33, lifetime avg. 23 degC > drive /dev/ada1: HGST HTS721010A9E630, S/N: JR10006PGYD6ZE, Temp. 28 > degC, min/max, cycle: 24/33, lifetime: 20/33, lifetime avg. 24 degC > drive /dev/ada2: HGST HTS721010A9E630, S/N: JR10006PGYTR8E, Temp. 27 > degC, min/max, cycle: 24/33, lifetime: 19/33, lifetime avg. 24 degC > drive /dev/ada3: HGST HTS721010A9E630, S/N: JR10006PGYK1YE, Temp. 27 > degC, min/max, cycle: 23/31, lifetime: 19/33, lifetime avg. 23 degC > [root@kabini1, /etc, 7:32:58pm] 457 % Okay, I think I get the idea. How about this? #!/bin/sh echo -n "drive $1: " smartctl -a $1 | awk -F ":" ' { gsub("Celsius", "degC", $0); gsub(":[ \t]*", ":", $0); } /Device Model/ { printf("%s ", $2); } /Serial Number/ { printf("S/N: %s, ", $2); } /Current Temperature/ { printf("Temp: %s, ", $2); } /Power Cycle Min\/Max Temperature/ { printf("min/max, cycle: %s, ", $2); } /Lifetime Min\/Max Temperature/ { printf("lifetime: %s, ", $2); } /Lifetime Average Temperature/ { printf("lifetime avg: %s\n", $2); } ' For "good style", make a [ -f for $1 before continuing, and add a usage information message if $1 is not given. Also point your finger at my gsub() and "space collapsing" magic and say: "What a stupid way to do it!", because I can imagine that there's a much better way to do it. And note the "C contaminated" use of awk. :-) > Funny you mention grep, I had a similar conversation on the NetBSD list > last week & everyone there suggested using awk alone to 'grep' out the > lines I wanted. The idea of awk is that you intend to postprocess the text, not just printing it 1:1 (what grep would do). In such a case, using awk's builtin pattern matching is the way to go, because awk is a "pattern-directed scanning and processing language", according to its manpage. > However, over there, the temp output I wanted was all in > 1 line, just not formatted as I wanted it. That would have been a case for grep. -- Polytropon Magdeburg, Germany Happy FreeBSD user since 4.0 Andra moi ennepe, Mousa, ...
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20151005063405.e0a6030c.freebsd>