Сценарии Shell: Изменение во входном потоке, не работающем, как желаемый

Я пытаюсь создать сценарий оболочки, который может считать слова и строки в файле. (да, я знаю, что можно сделать тот туалет использования, но только ради изучения циклов),

Код

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

Кто-либо мог разъяснить то, что я делаю неправильно?спасибо.

2
задан 12 March 2015 в 08:16

1 ответ

Вероятно, для последней строки, или где-нибудь промежуточный, существует пустая строка. Когда Вы работаете 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 и два execs:

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
0
ответ дан 3 December 2019 в 00:42

Другие вопросы по тегам:

Похожие вопросы: