抱歉,如果它又长又混乱,但我有三个文件,即cat
、dog
和cow
。
我的代码是这样的:
echo -e "Enter file name: \c"
read filename #saves variable
if [ -e "$filename" ]
then
total =$(wc -l $filename) #calculate total lines in the*CAT* file
echo There are $total #prints There are *numberoflines*
echo $total > newfile #writes the answer into a newly created file
else
echo $filename not found
fi
当我运行上面的代码时,会发生以下情况:
Enter file name : cat
There are 5 cat
(我在提示符下输入cat
,然后看到文件中的行数。)
当我运行名为5 行的5 cat
文件时,它会给我一个输出。cat
但是假设当我想同时运行所有三个文件时,我该怎么办?
假设我希望它显示如下
Enter file name : cat dog cow
5 cat
2 dog
14 cow
Total 21
不幸的是,它显示
file not found
当我同时运行所有文件时,但是如果我在文件上逐个运行脚本,则没有任何问题。
答案1
除了注释中已经提到的语法问题之外,代码的主要问题是您正在将多个文件名读取到单个字符串中,然后使用该单个字符串作为单个文件名。
让我们重新考虑一下您想要做什么,而不是纠正脚本的这方面。
您希望用户提供一个或多个文件名,然后您希望脚本计算每个文件中的行数并输出每个文件中的行数以及总行数。您还希望允许用户将此信息存储到输出文件中。如果文件名不存在,您希望用户知道这一点。
该脚本可能如下所示:
#!/bin/sh -
wc -l -- "$@"
在不存储输出的情况下进行测试:
$ ./script.sh cat dog cow
5 cat
2 dog
14 cow
21 total
使用不存在的文件名调用脚本:
$ ./script.sh cat dog cow hamster
5 cat
2 dog
14 cow
wc: hamster: No such file or directory
21 total
将输出存储在文件中:
$ ./script.sh cat dog cow hamster >output
wc: hamster: No such file or directory
$ cat output
5 cat
2 dog
14 cow
21 total
脚本中的"$@"
将会替换为命令行参数列表,每个参数都单独引用。这意味着,如果您在命令行上使用cat
,dog
和调用脚本,脚本中的 将会扩展到该列表。cow
"$@"
该wc
实用程序已经执行了所有必要的操作,包括为您提供所有给定文件的总计,因此我们需要做的就是使用-l
脚本命令行上列出的文件名上的选项来调用它,以使其计算行数。
默认情况下,输出写入标准输出。这使脚本用户可以自由地将输出轻松重定向到他们想要的任何位置。
另请注意,使用制表符完成或文件名通配模式为脚本提供命令行参数比在交互式提示符下手动写入每个文件名要方便得多。在这种情况下,它也大大简化了脚本的代码。
你什么可能想要做的额外检查是,如果未提供,则向用户投诉任何文件名。否则该wc
实用程序将开始从标准输入读取,这会有些混乱。
您可以通过多种方式执行此操作,但我将在此处展示增强脚本的两种变体:
#!/bin/sh -
if [ "$#" -eq 0 ]; then
echo 'expected to get filename argument(s)' >&2
exit 1
fi
wc -l -- "$@"
它查看$#
值,即脚本获取的命令行参数的数量。如果该值为零,则该if
语句将分支到echo
,这将输出诊断消息,然后终止脚本。
#!/bin/sh -
wc -l -- "${@?expected to get filename argument(s)}"
这做了类似的事情,但使用了非常不同的机制。如果为空或未设置,扩展${variable?word}
将导致诊断消息word
写入输出"$@"
,并且还将终止脚本。
这可能看起来像:
$ ./script.sh
./script.sh[3]: @: expected to get filename argument(s)