Я пытаюсь создать сценарий оболочки, который может считать слова и строки в файле. (да, я знаю, что можно сделать тот туалет использования, но только ради изучения циклов),
Код
echo "enter filename"
read f
if [ -s $f ]
then
terminal=`tty`
exec < $f
nol=0
now=0
while read line
do
nol=`expr $nol + 1`
set $line
now=`expr $now + $#`
done
echo "No.of lines in the file =$nol"
echo "No.of words in the file =$now"
exec < $terminal
fi
ожидаемый вывод:
No.of lines in the file =3
No.of words in the file =166
Эффективная выходная мощность:
$ sh wc.sh
enter filename
spock.txt
CLUTTER_IM_MODULE='xim'
COLORTERM='gnome-terminal'
COMPIZ_BIN_PATH='/usr/bin/'
COMPIZ_CONFIG_PROFILE='ubuntu'
DBUS_SESSION_BUS_ADDRESS='unix:abstract=/tmp/dbus-PfcwnNxO9c'
DEFAULTS_PATH='/usr/share/gconf/ubuntu.default.path'
DESKTOP_SESSION='ubuntu'
DISPLAY=':0'
...
XDG_MENU_PREFIX='gnome-'
XDG_RUNTIME_DIR='/run/user/1000'
XDG_SEAT='seat0'
XDG_SEAT_PATH='/org/freedesktop/DisplayManager/Seat0'
XDG_SESSION_ID='c1'
XDG_SESSION_PATH='/org/freedesktop/DisplayManager/Session0'
XDG_VTNR='7'
XMODIFIERS='@im=ibus'
_='/bin/sh'
f='spock.txt'
line=''
nol='2'
now='66'
terminal='/dev/pts/0'
No.of lines in the file =3
No.of words in the file =166
Кто-либо мог разъяснить то, что я делаю неправильно?спасибо.
Вероятно, для последней строки, или где-нибудь промежуточный, существует пустая строка. Когда Вы работаете set
без аргументов это печатает каждый переменный набор в текущей оболочке. От спецификации POSIX:
Если никакие опции или аргументы не будут указаны, установите, то напишу имена и значения всех переменных оболочки в сортирующей последовательности текущей локали.
Это отбросит Ваше вычисление, так как это не устанавливает аргументы пустому списку - Вы будете добавлять подсчет слов предыдущей строки снова.
Вы получаете тот вывод потому что $line
пусто, поэтому что необходимо сделать, проверить, ли это на самом деле, пусто:
while read line
do
nol=`expr $nol + 1`
if [ -n "$line" ]
then
set $line
now=`expr $now + $#`
fi
done
Кроме этого, вместо exec <$f
, Я предложил бы использовать:
while read ..
do
...
done < "$f"
Каково Ваше выполнение теперь:
terminal=`tty`
exec < $f
...
exec < $terminal
Вы перенаправляете целый сценарий, тогда как Вам только нужно перенаправление для цикла. Можно пропустить вызов к tty
и два exec
s:
if [ -s $f ]
then
nol=0
now=0
while read line
do
...
done < "$f"
...
fi
И используйте арифметическое расширение вместо замены команды с expr
:
nol=$((nol + 1))
now=$((now + $#))
И всегда, всегда, заключают Ваши переменные в кавычки, если Вы явно не хотите разделить:
[ -s "$f" ]
exec < "$f"
Рассмотрите то, что происходит когда f
содержит пробелы:
f="there are spaces in this filename"
[ -s $f ]
exec < $f
Вы получите ошибки, потому что однажды $f
заменяется его содержанием, каждое слово в нем будет замечено отдельно:
bash: [: too many arguments
bash: $f: ambiguous redirect