Intereting Posts
Математическое соединение между SZ RSS и VSZ в ps o / p? Замените только шестнадцатеричные цифры, игнорируйте, если их меньше или больше, чем 8 цифр Использование команды sed Как извлечь строки, начинающиеся с шаблона и фрагментов между двумя шаблонами? Прокрутка экрана или выключение паузы Строка состояния экрана GNU – как заставить отображать имена сеансов оболочки? Предсказывать имя файла перед загрузкой с URL-адреса, в сценарии оболочки Считается ли синтаксис подстановки команд $ () оператором или командой? Значение, назначенное внутри функциональной переменной, всегда пусто Текстовый редактор для печати кода на C ++ Использование eval и sed для выполнения подсчета и управления скриптами Недопустимый формат модуля Удаление текста между двумя конкретными строками Переименование папок на основе словаря в виде файла CSV? Где загрузить RPM? Спутниковый скаут RHN не будет толкать

Ошибка при подсчете символов в файле

У меня есть исходный код, чтобы найти несколько слов и символов в файле:

#!/bin/bash w=0 cc=0 for i in `cat $1` do j=$i echo $j w=$(($w+1)) c=`expr $j:'.*'` cc=$(($cc+$c)) done echo "no of characters" $cc echo "no of words" $w 

Но когда я запускаю его в терминале, отображается следующее сообщение об ошибке: ./countWordChar 1.c hello ./countWordChar: строка 10: 0+hello:.* : Синтаксическая ошибка в выражении (токен ошибки ":.*" ) нет символов 0 нет слов 1

10-я строка в коде – cc=$(($cc+$c)) . По-видимому, значение переменной c не является числом символов слова, а само слово.

И мой файл 1.c-файла выглядит так:

 hello world hello 

Что не так в коде?

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

Утилита expr анализирует свои аргументы как выражение. Операторы должны отображаться как автономные аргументы.

 expr "$j" : '.*' 

Выше expr передается 4 аргумента: expr , содержимое $j и .* . Предполагая, что содержимое $j не ( или ! (Или такие вещи, как length с некоторыми реализациями), expr будет под этим как оператор сопоставления шаблонов, применяемый к контенту $j .

Чтобы сделать его более надежным, вам нужно:

 expr " $j" : '.*' - 1 

(второй аргумент, начинающийся с пробела, не может быть распознан как оператор expr, поэтому он работает над проблемами, отмеченными выше).

С

 expr $j:'.*' 

Это будет два аргумента ( expr и содержимое $j за которым следует :.* (Предполагая, что $j не содержит пустых или подстановочных знаков, см. Ниже)). Поскольку expr видит только один аргумент (помимо имени команды), запрос на операцию отсутствует, это всего лишь один аргумент строки, который expr просто отсылает обратно.

Теперь с вашим кодом возникает ряд других проблем:

Расширение переменной и подстановка команд ( $((...)) или устаревшая форма `...` вы используете), когда unquoted проходит split+glob . Вы хотите, чтобы split часть для части `cat $1` (должна была быть $(cat < "$1") ), чтобы разделить ее на слова, но не на glob-часть, так как в противном случае они бы расширяли * слова, например, в списке файлов в текущем каталоге; и все другие переменные расширения должны быть указаны (не обязательно в назначениях, но цитаты там не вредят).

Кроме того, вы не можете использовать echo для произвольных данных .

Так должно быть:

 w=0 c=0 set -f # disable glob for i in $(cat < "$1"); do printf '%s\n' "$i" w="$((w + 1))" c="$(expr " $i" : '.*' + "$c" - 1)" done 

С помощью expr $j:'.*' Команда expr получает один (1) аргумент.
Команда expr не могла этого понять.

Команда expr требует, чтобы каждый аргумент четко разделялся:

 expr "$j" ":" '.*' 

Это будет три (3) аргумента, выданных команде expr . Кавычки " вокруг : самом деле не требуются. И лучше использовать пробел перед строкой в $j чтобы избежать некоторых неверных истолкований, так как это:

 expr " $j" : '.*' 

Это сделает ваш скрипт похожим на это:

 #!/bin/dash w=0 cc=0 for i in `cat $1`; do echo "$j" w=$(($w+1)) c=`expr " $i" : '.*'` cc=$((cc+c)) done echo "no of characters" $cc echo "no of words" $w 

Но это скорее скрипт тире, чем скрипт bash (вот как вы отметили свой вопрос).
Упрощенный сценарий bash будет выглядеть следующим образом:

 #!/bin/bash w=0 cc=0 for i in $(< $1) do ((w++)) cc=((cc+${#i})) done echo "no of characters" "$cc" echo "no of words" "$w" 

$(< $1) эквивалентен $(cat $1) но немного быстрее. Чтобы увеличить w, это меньше, чем w++ . А для подсчета количества символов мы можем использовать длину $i как ${#i} .

Или даже короче:

 #!/bin/bash w=0 cc=0 for i in $(< $1) do (( w++ , cc += ${#i} )) done printf "no of characters %s\nno of words %s\n" "$cc" "$w" 

Используя bash (из 2.04-devel и up) запятую , оператор и используя cc += ${#i} как эквивалент cc = cc + ${#i} .