Apart from the syntax issues already mentioned in comments, your main issue with the code is that you are reading what you perceive to be multiple filenames into a single string, then you use that single string as a single filename.
Instead of correcting that aspect of the script, let's rethink what it is that you want to do.
You want the user to supply one or several filenames, then you want your script to count the number of lines in each and output the number of lines in each file, along with the total number of lines. You also want to allow the user to store this information to an output file. If a filename does not exist, you want the user to by made aware of this.
The script could look like this:
#!/bin/sh -
wc -l -- "$@"
Testing this without storing the output:
$ ./script.sh cat dog cow
5 cat
2 dog
14 cow
21 total
Calling the script with a filename that does not exist:
$ ./script.sh cat dog cow hamster
5 cat
2 dog
14 cow
wc: hamster: No such file or directory
21 total
Storing the output in a file:
$ ./script.sh cat dog cow hamster >output
wc: hamster: No such file or directory
$ cat output
5 cat
2 dog
14 cow
21 total
The "$@"
in the script will be replaced by the list of command line arguments, each individually quoted. This means that if you call your script with cat
, dog
and cow
on the command line, the "$@"
in the script will expand to that list.
The wc
utility already performs all the necessary things, including providing you with the grand total across all the given files, so all we need to do is to call it with its -l
option on the filenames listed on the script's command line to get it to count lines.
The output is written to standard output by default. This gives the user of script the freedom to easily redirect the output to wherever they want.
Also notice that it's far more convinient to give a script command line arguments, using tab completion or filename globbing patterns, than to write each filename in by hand at an interactive prompt. In this case, it also greatly simplifies the script's code.
What you may want to do as an extra check, is to complain to the user if the did not supply any filenames. The wc
utility will otherwise start reading from standard input, which would be somewhat confusing.
You could do this in many ways, but I'll show two variants of the enhanced script here:
#!/bin/sh -
if [ "$#" -eq 0 ]; then
echo 'expected to get filename argument(s)' >&2
exit 1
fi
wc -l -- "$@"
This looks at the $#
value, which is the number of command line arguments that the script got. If this is zero, the if
statement will branch to the echo
, which will output a diagnostic message and then terminate the script.
#!/bin/sh -
wc -l -- "${@?expected to get filename argument(s)}"
This does a similar thing but using a very different mechanics. The ${variable?word}
expansion will result in the diagnostic message in word
being written to the output if "$@"
is empty or unset, and it will also terminate the script.
This may look like:
$ ./script.sh
./script.sh[3]: @: expected to get filename argument(s)
total =...
. (3) You're missing afi
.[ -e "cat dog cow" ]
, but a file with name"cat dog cow"
does not exist.-e Enter file name: read: Command not found. filename: Undefined variable.
file not found
when run with thetcsh
shell. It says-e Enter file name: \c
followed by the errorread: Command not found.
. If you run it withbash
, it terminates withscript: line 10: syntax error: unexpected end of file
. What shell are you actually using?read
command to get the file name(s) I suggest to use command line arguments. You could run your script aslinecounter.sh cat dog cow
and implement it likefor filename in "$@"; do ... ; done