Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Get only one line of the output of a command

63 views
Skip to first unread message

Cecil Westerhof

unread,
Nov 21, 2017, 4:59:06 AM11/21/17
to
In Python I have the following code:
output = check_output(temp_cmd).decode('utf-8').split('\n')
array = [elem for elem in output if 'CPUTIN' in elem]
if len(array) != 1:
print('ERROR: {} did not give exactly one line'.format(temp_cmd[0]))
exit(1)
return float(array[0].split()[1][:-2])

How would I rewrite this in TCL?
What it does it puts the output of temp_cmd into output.
Then it selects the lines that contain 'CPUTIN' and put it in array.
This should be exact one element.
It then returns the second value from this element.

--
Cecil Westerhof
Senior Software Engineer
LinkedIn: http://www.linkedin.com/in/cecilwesterhof

Arjen Markus

unread,
Nov 21, 2017, 5:34:42 AM11/21/17
to
Something along these lines (untested):

set result {}
foreach line [split [exec temp_cmd] \n] {
if { [string first "CPUTIN" $line] } {
lappend result $line
}
}
if { [llength $results] != 1 } {
puts "Error: too many lines!"
} else {
do what needs to be done
}

Alternatively, you can use [regexp] to filter out the lines that contain "CPUTIN":

set results [regexp -inline -all {[^\nCPUTIN[^\n]*\n} [exec temp_cmd]\n]

where the trailing \n is to ensure the last line is also checked.

Regards,

Arjen

Cecil Westerhof

unread,
Nov 21, 2017, 6:59:05 AM11/21/17
to
Arjen Markus <arjen.m...@gmail.com> writes:

> On Tuesday, November 21, 2017 at 10:59:06 AM UTC+1, Cecil Westerhof wrote:
>> In Python I have the following code:
>> output = check_output(temp_cmd).decode('utf-8').split('\n')
>> array = [elem for elem in output if 'CPUTIN' in elem]
>> if len(array) != 1:
>> print('ERROR: {} did not give exactly one line'.format(temp_cmd[0]))
>> exit(1)
>> return float(array[0].split()[1][:-2])
>>
>> How would I rewrite this in TCL?
>> What it does it puts the output of temp_cmd into output.
>> Then it selects the lines that contain 'CPUTIN' and put it in array.
>> This should be exact one element.
>> It then returns the second value from this element.
>>
>> --
>> Cecil Westerhof
>> Senior Software Engineer
>> LinkedIn: http://www.linkedin.com/in/cecilwesterhof
>
> Something along these lines (untested):
>
> set result {}
> foreach line [split [exec temp_cmd] \n] {
> if { [string first "CPUTIN" $line] } {

Should be:
if { [string first "CPUTIN" $line] == 0} {

Is better as my Python script, because the line always starts with it.

> lappend result $line
> }
> }
> if { [llength $results] != 1 } {
> puts "Error: too many lines!"
> } else {
> do what needs to be done
> }
>
> Alternatively, you can use [regexp] to filter out the lines that contain "CPUTIN":
>
> set results [regexp -inline -all {[^\nCPUTIN[^\n]*\n} [exec temp_cmd]\n]
>
> where the trailing \n is to ensure the last line is also checked.

Does not work, but the first one works, so I will look in that one
later.


Thanks.

Cecil Westerhof

unread,
Nov 21, 2017, 8:14:05 AM11/21/17
to
Cecil Westerhof <Ce...@decebal.nl> writes:

> In Python I have the following code:
> output = check_output(temp_cmd).decode('utf-8').split('\n')
> array = [elem for elem in output if 'CPUTIN' in elem]
> if len(array) != 1:
> print('ERROR: {} did not give exactly one line'.format(temp_cmd[0]))
> exit(1)
> return float(array[0].split()[1][:-2])
>
> How would I rewrite this in TCL?
> What it does it puts the output of temp_cmd into output.
> Then it selects the lines that contain 'CPUTIN' and put it in array.
> This should be exact one element.
> It then returns the second value from this element.

This is what it has become:
proc getCPUTemp {} {
set result {}

foreach line [split [exec sensors] \n] {
if { [string first "CPUTIN: " ${line}] == 0} {
lappend result [lindex [regexp -all -inline {\S+} $line] 1]
}
}
if { [llength ${result}] != 1} {
puts "Got not exactly one value."
exit 1
}
return ${result}

Rich

unread,
Nov 21, 2017, 11:53:34 AM11/21/17
to
If you want to see an alternative, that uses regexp and works (Arjen's
version failed because your original spec didn't clearly indicate (to
us Tcl'ers) that CPUTIN: was a line prefix), this is also a
possibility:

proc getCPUTemp {} {
if {1 != [regexp -all -line ^CPUTIN:.*$ [exec sensors] answer} {
error "Did not get a single line from \[exec sensors\] output"
}
return $answer
}

Explaining:
The -line option to regexp causes the anchors ^ and $ to also anchor to
newlines as well as the start and ends of the string.

The -all causes regexp to search for all matches in the input (and
regexp's return value in this form [form without -inline option] is
documented to be a count of the number of matches found).

^CPUTIN:.*$ This finds lines that begin with CPUTIN: and the .*$
causes the regex engine to capture the remainer of the line as part of
the match. The ^ is the "start" anchor, in this case looking for the
start of lines, $ is the "end" anchor, in this case looking for the end of a
line.

answer is regexp's result variable, the item matched (technically in
this form the last item matched) will be stored here, if there are
any matches.

The 'if' simply checks regexp's return value (a count of the number of
matches found. If it is not 1, trigger an error.

Otherwise return contents of 'answer' (because it contains the matched
line, and there was only 1, so it is the line that is desired.

Cecil Westerhof

unread,
Nov 21, 2017, 4:44:04 PM11/21/17
to
There was missing a ']'. I changed it to (I also only want the
temperature):
proc getCPUTemp {} {
if {1 != [regexp -all -line ^CPUTIN:.*$ [exec sensors] answer]} {
error "Did not get a single line from \[exec sensors\] output"
}
return [lindex [regexp -all -inline {\S+} ${answer}] 1]

Rich

unread,
Nov 21, 2017, 5:42:42 PM11/21/17
to
Indeed. The danger of copy/pasting from a tclsh to usenet.... :)

> I changed it to (I also only want the
> temperature):
> proc getCPUTemp {} {
> if {1 != [regexp -all -line ^CPUTIN:.*$ [exec sensors] answer]} {
> error "Did not get a single line from \[exec sensors\] output"
> }
> return [lindex [regexp -all -inline {\S+} ${answer}] 1]
> }

That works, an alternative would be to wrap that into the first regexp
with a set of capturing paren's for the temp and eliminate the
tokenizing regex and the lindex.

Andreas Leitgeb

unread,
Nov 22, 2017, 12:06:53 PM11/22/17
to
Cecil Westerhof <Ce...@decebal.nl> wrote:
> array = [elem for elem in output if 'CPUTIN' in elem]

Fwiw, running "sensors" on my Ubuntu 16.04 laptop does not seem
to have any line with "CPUTIN" (and no "CTRUMP", either, scnr)

Maybe your script is only meant for certain hardware that does
have such an entry, just don't assume that it would be so on all
linux machines. Or, rather make the keyword configurable.

Gerald Lester

unread,
Nov 22, 2017, 2:15:25 PM11/22/17
to
On my Ubuntu 17.10, I get:
iwlwifi-virtual-0
Adapter: Virtual device
temp1: +33.0°C

coretemp-isa-0000
Adapter: ISA adapter
Package id 0: +41.0°C (high = +100.0°C, crit = +100.0°C)
Core 0: +39.0°C (high = +100.0°C, crit = +100.0°C)
Core 1: +39.0°C (high = +100.0°C, crit = +100.0°C)
Core 2: +40.0°C (high = +100.0°C, crit = +100.0°C)
Core 3: +40.0°C (high = +100.0°C, crit = +100.0°C)

acpitz-virtual-0
Adapter: Virtual device
temp1: +42.0°C (crit = +98.0°C)

asus-isa-0000
Adapter: ISA adapter
cpu_fan: 0 RPM

pch_skylake-virtual-0
Adapter: Virtual device
temp1: +56.0°C

-- So ain't there either!


--
+----------------------------------------------------------------------+
| Gerald W. Lester, President, KNG Consulting LLC |
| Email: Gerald...@kng-consulting.net |
+----------------------------------------------------------------------+

Cecil Westerhof

unread,
Nov 23, 2017, 3:44:06 AM11/23/17
to
OK: I have to look into that then.
0 new messages