How to read from the stdin with nim script? - nim-lang

How would i read from the stdin via nimscript?
i've tried:
if readLine(stdin) == "yes":
exec buildCommand
i've run the script with
nim c build.nims
i receive
build.nims(50, 13) Error: undeclared identifier: 'stdin'

I don't think nimscript supports reading from stdin just yet.
You might want to create a feature request for this: https://github.com/nim-lang/Nim/issues

var f : File;
discard f.open(0, fmRead)
let s = f.readLine()
echo "INPUT " & s
... works -- stdin has file handle 0

This is now implemented in nimscript in devel: readAllFromStdin().
It will be available in Nim v0.20.0+ (yet to be released as of 2019-05-21).

Related

how to redirect this perl script's output to file?

I don't have much experience with perl, and would appreciate any/all feedback....
[Before I start: I do not have access/authority to change the existing perl scripts.]
I run a couple perl scripts several times a day, but I would like to begin capturing their output in a file.
The first perl script does not take any arguments, and I'm able to "tee" its output without issue:
/asdf/loc1/rebuild-stuff.pl 2>&1 | tee $mytmpfile1
The second perl script hangs with this command:
/asdf/loc1/create-site.pl --record=${newsite} 2>&1 | tee $mytmpfile2
FYI, the following command does NOT hang:
/asdf/loc1/create-site.pl --record=${newsite} 2>&1
I'm wondering if /asdf/loc1/create-site.pl is trying to process the | tee $mytmpfile2 as additional command-line arguments? I'm not permitted to share the entire script, but here's the beginning of its main routine:
...
my $fullpath = $0;
$0 =~ s%.*/%%;
# Parse command-line options.
...
Getopt::Long::config ('no_ignore_case','bundling');
GetOptions ('h|help' => \$help,
'n|dry-run|just-print' => \$preview,
'q|quiet|no-mail' => \$quiet,
'r|record=s' => \$record,
'V|noverify' => \$skipverify,
'v|version' => \$version) or exit 1;
...
Does the above code provide any clues? Other than modifying the script, do you have any tips for allowing me to capture its output in a file?
It's not hanging. You are "suffering from buffering". Like most programs, Perl's STDOUT is buffered by default. Like most programs, Perl's STDOUT is flushed by a newline when connected to a terminal, and block buffered otherwise. When STDOUT isn't connected to a terminal, you won't get any output until 4 KiB or 8 KiB of output is accumulated (depending on your version of Perl) or the program exits.
You could add $| = 1; to the script to disable buffering for STDOUT. If your program ends with a true value or exits using exit, you can do that without changing the .pl file. Simply use the following wrapper:
perl -e'
$| = 1;
$0 = shift;
do($0);
my $e = $# || $! || "$0 didn\x27t return a true value\n";
die($e) if $e;
' -- prog args | ...
Or you could fool the program into thinking it's connected to a terminal using unbuffer.
unbuffer prog args | ...

Perl anonymous pipe no output

Question
Why is nothing printed when using anonymous pipe, unless I print the actual data from pipe ?
Example
use strict;
use warnings;
my $child_process_id = 0;
my $vmstat_command = 'vmstat 7|';
$child_process_id = open(VMSTAT, $vmstat_command) || die "Error when executing \"$vmstat_command\": $!";
while (<VMSTAT>) {
print "hi" ;
}
close VMSTAT or die "bad command: $! $?";
Appears to hang
use strict;
use warnings;
my $child_process_id = 0;
my $vmstat_command = 'vmstat 7|';
$child_process_id = open(VMSTAT, $vmstat_command) || die "Error when executing \"$vmstat_command\": $!";
while (<VMSTAT>) {
print "hi" . $_ ;
# ^^^ Added this
}
close VMSTAT or die "bad command: $! $?";
Prints
hiprocs -----------memory---------- ---swap-- -----io---- -system-- -----cpu------
hi r b swpd free buff cache si so bi bo in cs us sy id wa st
hi 1 0 0 7264836 144200 307076 0 0 0 1 0 14 0 0 100 0 0
etc...
Expected behaviour
Would be to print hi for every line of output of vmstat for the first example.
Versions
perl, v5.10.0
GNU bash, version 3.2.51
Misc
It also appears to hang when using chomp before printing the line (which i thought only removes newlines).
I feel like i'm missing something fundamental to how the pipe is read and processed but could not find a similar question. If there is one then dupe this and I'll have a look at it.
Any further information needed just ask.
Alter
print "hi";
to
print "hi\n";
and it also "works"
the reason it fails is that output is line buffered by default
setting $| will flush the buffer straight away
If set to nonzero, forces a flush right away and after every write or print on the currently selected output channel. Default is 0 (regardless of whether the channel is really buffered by the system or not; "$|" tells you only whether you've asked Perl explicitly to flush after each write). STDOUT will typically be line buffered if output is to the terminal and block buffered otherwise. Setting this variable is useful primarily when you are outputting to a pipe or socket, such as when you are running a Perl program under rsh and want to see the output as it's happening. This has no effect on input buffering. See the getc entry in the perlfunc manpage for that. (Mnemonic: when you want your pipes to be piping hot.)

Why do I get the error "Received usmStatsUnknownUserNames.0 Report-PDU with value 1" when I try to connect to my device using Net::SNMP?

I am trying to write a Perl script to do an SNMP get. It should work like the following command:
snmpget -v 3 -l authNoPriv -a MD5 -u V3User -A V3Password 10.0.1.203 sysUpTime.0
Returns:
SNMPv2-MIB::sysUpTime.0 = Timeticks: (492505406) 57 days, 0:04:14.06
But my Perl script returns the following:
ERROR: Received usmStatsUnknownUserNames.0 Report-PDU with value 1 during synchronization.
Last but not least, here is the Perl script:
use strict;
use warnings;
use Net::SNMP;
my $desc = 'sysUpTime.0';
my ($session, $error) = Net::SNMP->session(
-hostname => '10.0.1.202',
-version => 'snmpv3',
-username => 'V3User',
-authprotocol => 'md5',
-authpassword => 'V3Password'
);
if (!defined($session)) {
printf("ERROR: %s.\n", $error);
exit 1;
}
my $response = $session->get_request($desc);
my %pdesc = %{$response};
my $err = $session->error;
if ($err){
return 1;
}
print %pdesc;
exit 0;
I called the Perl script and snmpget on the same (Linux) machine. What could be causing this and how can I fix it?
As PrgmError points out, you're using a different IP address in your Perl script than in your snmpget command; I would double check that. The particular error you're getting indicates that your username is wrong; if the IP mismatch was simply a typo in your question, I would double check the username next.
A few other points about your Perl script:
Use die
You should use die instead of printf and exit since die will print the line number where it was invoked. This will make debugging your script much easier if there are multiple places it could fail:
die "Error: $error" if not defined $session;
will print something like
Error: foo bar at foo.pl line 17.
Also, using return inside an if statement doesn't make any sense; I think you meant to use
if ($err) {
exit 1;
}
but you should die with the specific error message you get instead of silently failing:
die $err if $err;
Fix arguments to get_request
Your invocation of the get_request method looks wrong. According to the docs, you should be calling it like this:
my $response = $session->get_request(-varbindlist => [ $oid ]);
Note that Net::SNMP only works with numeric OIDs, so you'll have to change sysUpTime.0 to 1.3.6.1.2.1.1.3.0.
Looking at your script I noticed that hostname value has 10.0.1.202
but the snmpget command you're using has 10.0.1.203
wrong IP by any chance?

How to make R script takes input from pipe and user given parameter

I have the following R script (myscript.r)
#!/usr/bin/env Rscript
dat <- read.table(file('stdin'), sep=" ",header=FALSE)
# do something with dat
# later with user given "param_1"
With that script we can run it the following way;
$ cat data_no_*.txt | ./myscript.r
What I want to do is to make the script takes additional parameter from user:
$ cat data_no_*.txt | ./myscript.r param_1
What should I do to modify the myscript.r to accommodate that?
For very basic usage, have a look at ?commandArgs.
For more complex usage, two popular packages for command-line arguments and options parsing are getopt and optparse. I use them all the time, they get the job done. I also see argparse, argparser, and GetoptLong but have never used them before. One I missed: Dirk recommended that you look at docopt which does seem very nice and easy to use.
Finally, since you seem to be passing arguments via pipes you might find this OpenRead() function useful for generalizing your code and allowing your arguments to be pipes or files.
I wanted to test docopt so putting it all together, your script could look like this:
#!/usr/bin/env Rscript
## Command-line parsing ##
'usage: my_prog.R [-v -m <msg>] <param> <file_arg>
options:
-v verbose
-m <msg> Message' -> doc
library(docopt)
opts <- docopt(doc)
if (opts$v) print(str(opts))
if (!is.null(opts$message)) cat("MESSAGE: ", opts$m)
## File Read ##
OpenRead <- function(arg) {
if (arg %in% c("-", "/dev/stdin")) {
file("stdin", open = "r")
} else if (grepl("^/dev/fd/", arg)) {
fifo(arg, open = "r")
} else {
file(arg, open = "r")
}
}
dat.con <- OpenRead(opts$file_arg)
dat <- read.table(dat.con, sep = " ", header = FALSE)
# do something with dat and opts$param
And you can test running:
echo "1 2 3" | ./test.R -v -m HI param_1 -
or
./test.R -v -m HI param_1 some_file.txt
We built littler to support just that via its r executable.
Have a look at its examples, it may fit your bill.

Input loop with FIFO problems

I'm having some trouble using FIFOs for stdin.
I have a script like this:
#!/usr/bin/env ruby
while true do
data = gets
puts "Got: #{data}"
end
Then I run it like:
$ ./script < input.fifo &
$ echo testdata > input.fifo
It will print something like:
Got: testdata
Got:
Got:
Got:
Got:
Got:
etc.
My suspicion is that something is wrong with the FIFO. That something is not getting cleared out after it is sent to the script.
I tried the same thing with a C program with a similar input loop using a scanf("%d" ...) and it acted like this:
$ echo 1 > input.fifo
Got: 1
Got: 1
Got: 1
Got: 1
etc.
So it would seem that the last thing in the FIFO gets stuck there. In the ruby example, it is a null line, because gets captures the \n. In the second it is the 1 itself.
Can anyone offer any insight?
Thanks!
The situation is simple, after:
'echo 1 > input.fifo', the file 'input.fifo' was opened, "1" was written to it,
and it is closed.
The problem is that it is closed. When fifo closed from writing side, this is equal "end of file" for reading side. So if you check return code from "scanf" in your C example it will be equal to EOF constant.
And after "end of file" when you read all data from fifo, and try read something,
the "reading" code will alaways return immediately and report "end of file".

Resources