Script to Run Against Stdin If No Arg; Otherwise Input File =Argv[0]

Script to run against stdin if no arg; otherwise input file =ARGV[0]

You can eliminate the first five lines entirely.

From Pickaxe

$<: An object that provides access to
the concatenation of the contents of
all the files given as command-line
arguments or $stdin (in the case where
there are no arguments). $< supports
methods similar to a File object:
binmode, close, closed?, each,
each_byte, each_line, eof, eof?, file,
filename, fileno, getc, gets, lineno,
lineno=, path, pos, pos=, read,
readchar, readline, readlines, rewind,
seek, skip, tell, to_a, to_i, to_io,
to_s, along with the methods in
Enumerable. The method file returns a
File object for the file currently
being read. This may change as $<
reads through the files on the command
line. [r/o]

Therefore:

print $<.read

Kernel.gets is shorthand for $<.gets, so:

while s = gets
puts s
end

How to read from stdin or from a file if no data is piped in Python?

Process your non-filename arguments however you'd like, so you wind up with an array of non-option arguments, then pass that array as the parameter to fileinput.input():

import fileinput
for line in fileinput.input(remaining_args):
process(line)

Ruby Switch Between File and Standard Input

See: ...run against stdin if no arg; otherwise input file =ARGV

How can I tell if no arguments have been given and nothing is coming in on stdin?

if (@ARGV == 0 && -t STDIN && -t STDERR) { 
print STDERR "$0: WARNING: reading input from keyboard, type ^D for EOF, ^C to intr.\n";
}

How to read from a file or standard input in Bash

The following solution reads from a file if the script is called with a file name as the first parameter $1 and otherwise from standard input.

while read line
do
echo "$line"
done < "${1:-/dev/stdin}"

The substitution ${1:-...} takes $1 if defined. Otherwise, the file name of the standard input of the own process is used.

How to open a filehandle with an existing variable in perl?

That's precisely what the null filehandle <> does

Input from <> comes either from standard input, or from each file listed on the command line.

So all you need is

while (<>) { 
...
}

(see the rest of what docs say about it)

Another, in some cases safer option, is to use a double diamond bracket

while (<<>>) { } 

Using double angle brackets inside of a while causes the open to use the three argument form (with the second argument being <), so all arguments in ARGV are treated as literal filenames (including "-"). (Note that for convenience, if you use <<>> and if @ARGV is empty, it will still read from the standard input.)

(again, please see the rest of what docs say)


For the second part of the question, and following a discussion in comments, it is worth noting that my $in = \*STDIN creates an alias to STDIN (not a copy); see this post. Then open-ing a file with such scalar (that had previously been assigned a reference to a typeglob) as filehandle merely redirects the original typeglob. So here once we open the $in filehandle then STDIN winds up connected to that file.

This is easily checked

perl -wE'
$in = \*STDIN;
say "\$in: $$in"; #--> *main::STDIN
print while <$in>; # type input, then Ctrl-D
open $in, "<", $ARGV[0] or die $!;
say "\$in is: $$in"; #--> *main::STDIN
print while <$in>; # but prints the file
seek $in, 0, 0;
print while <STDIN>; # prints the file
' file

After we type in some input, which is printed back, and Ctrl-D, after open-ing the file the filehandle is shown to still be STDIN but it does print out that file. Then printing STDIN still prints the file.

The STDIN has been reconnected by open to the file; getting it back isn't simple. So if one is to actually associate STDIN with a lexical then better dupe it. See docs and the linked post.


As for the direct question -- yes, one can reassign a filehandle by open-ing it.

But the ... or die if ... syntax is wrong as one cannot chain conditionals like that.

However, I cannot reproduce the shown behavior as your code actually works for me (on 5.16 and 5.30 on Linux). My best guess then is that such code results in an "undefined behavior" and we get unpredictable and inconsistent behaviors.

Consider

E1 or E2 if E3;

where Es stand for Expressions. (This is for open(...) or die($!) if COND;)

What should if E3 apply to -- the lone E2 or the whole E1 or E2? There is no way to tell and what one may well get then is the dreaded "undefined behavior" (UB) -- it may actually work, sometimes/under some conditions/on some systems, or anything else may happen.

Now, there may be a little more to it: E2 if E3 cannot be a part of a condition so the interpretation of it all as E1 or (E2 if E3); is directly illegal syntax so perhaps in my program the statement is interpreted as

(E1 or E2) if E3;

which is fine (and works as intended, as it happens). However, the original statement still must be UB and on OP's system it doesn't work.

Thus if you do need to have a filehandle at a minimum can fix that by adding parenthesis

(open $in, '<', $ARGV[0] or die $!) if defined $ARGV[0];

But I'd recommend writing a nice and readable test instead of cramming it into one statement (and dup-ing STDIN to start with).

Using gets() gives No such file or directory error when I pass arguments to my script

It looks like you want to the user to type some input by reading a line from STDIN, the best way to do this is by calling STDIN.gets and not gets. So your line becomes:

word = STDIN.gets.chomp

This is documented as IO.gets. STDIN is an instance of IO.

Right now, you're executing Kernel.gets, which does something different (emphasis mine):

Returns (and assigns to $_) the next line from the list of files in ARGV (or $*), or from standard input if no files are present on the command line.

This appears to behave like STDIN.gets if ARGV is empty, but is not the same thing, hence the confusion.



Related Topics



Leave a reply



Submit