1

I need to read command line arguments. First arg is script name. second one is redirection operator i.e. "<" and third one is input filename. When I tried to use "$#", I got 0. When I used "$*", it gave me nothing. I have to use "<" this operator. My input file consists of all user input data. If I don't use the operator, It asks user for the input. Can someone please help me? Thank you !

Command Line :

./script_name < input_file

Script:

 echo "$*"       # gave nothing
 echo "$#"       # gave me 0

I need to read input filename and store it to some variable. Then I have to change the extension of it. Any help/suggestions should be appreciated.

6
  • ./script_name input_file, then echo $1. Commented Aug 1, 2016 at 20:32
  • I have to read all lines from my input file. It has all the user input. If I don't use that operator, It will prompt the user for input. Commented Aug 1, 2016 at 20:39
  • 2
    Show your script, or an equivalent example, so we can see exactly how it reads from standard input Commented Aug 1, 2016 at 20:44
  • I am using "for i in $(cat input_file); do ----My code and some read statements---; done" Commented Aug 1, 2016 at 20:46
  • @Rock26, see mywiki.wooledge.org/DontReadLinesWithFor Commented Aug 1, 2016 at 20:48

3 Answers 3

3

When a user runs:

./script_name <input_file

...that's exactly equivalent to if they did the following:

(exec <input_file; exec ./script_name)

...first redirecting stdin from input_file, then invoking the script named ./script_name without any arguments.

There are operating-system-specific interfaces you can use to get the filename associated with a handle (when it has one), but to use one of these would make your script only able to run on an operating system providing that interface; it's not worth it.

# very, very linux-specific, won't work for "cat foo | ./yourscript", generally evil
if filename=$(readlink /proc/self/fd/0) && [[ -e $filename ]]; then
  set -- "$@" "$filename" # append filename to the end of the argument list
fi

If you want to avoid prompting for input when an argument is given, and to have the filename of that argument, then don't take it on stdin but as an argument, and do the redirection yourself within the script:

#!/bin/bash

if [[ $1 ]]; then
  exec <"$1" # this redirects your stdin to come from the file
fi

# ...put other logic here...

...and have users invoke your script as:

./script_name input_file

Just as ./yourscript <filename runs yourscript with the contents of filename on its standard input, a script invoked with ./yourscript filename which invokes exec <"$1" will have the contents of filename on its stdin after executing that command.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks @charles. It works perfectly fine. I appreciate your help and time.
2

< is used for input redirection. And whatever is at the right side of < is NOT a command line argument.

So, when you do ./script_name < input_file , there will be zero (0) command line arguments passed to the script, hence $# will be zero.

For your puprpose you need to call your script as:

./script_name input_file

And in your script you can change the extension with something like:

mv -- "$1" "${1}_new_extension"

Edit: This was not what OP wanted to do.


Altough, there is already another spot on answer, I will write this for the sake of completeness. If you have to use the '<' redirection you can do something like this in your script.

while read filename; do
mv -- "$filename" "${filename}_bak"
done 

And call the script as, ./script < input_file. However, note that you will not be able to take inputs from stdin in this case.

4 Comments

Needs more quotes (ie. mv -- "$1" "${1}_new_extension"). The -- is necessary to support filenames that start with dashes.
@CharlesDuffy good points. I have edited. Although it seems that OP is trying to do something else, as is seen in the comments in question now..
Thanks @sps. I can not remove "<" operator. If I do that, script will prompt user for inputs. I don't want user to provide input as it is already there in that input_file.
@Rock26, to the contrary, you can in fact remove the < -- see my answer, showing how to do the same thing the < would do from within the script.
0

Unfortunately, if you're hoping to take redirection operators as arguments to your script, you're not going to be able to do that without surrounding your command line arguments in quotes:

./script_name "<input_file"

The reason for this is that the shell (at least bash or zsh) processes the command before ever invoking your script. When the shell interprets your command, it reads:

[shell command (./script_name)][shell input redirection (<input_file)]

invoking your script with quotes effectively results in:

[shell command (./script_name)][script argument ("<input_file")]

Sorry this is a few years late; hopefully someone will find this useful.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.