web-dev-qa-db-ja.com

ファイル内の文字をカウント中にエラーが発生しました

ファイル内のいくつかの単語や文字を見つけるためのソースコードがあります。

_#!/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変数の値はWordの文字数ではなく、Word自体です。

そして私の1.cファイルの内容はそのようなものです:

_hello world
hello
_

コードの何が問題になっていますか?

PS。ファイル内の文字をカウントする組み込みコマンドがあることは知っていますが、タスクに応じて前のコードを使用する必要があります。

1
Stranger

exprユーティリティは、引数を式として解析します。演算子はスタンドアロン引数として表示される必要があります。

expr "$j" : '.*'

上記では、exprに4つの引数が渡されます:expr$j:、および.*のコンテンツ。 $jのコンテンツが(または!(または一部の実装ではlengthのようなもの)ではないと仮定すると、exprは、:のコンテンツに適用される$jパターンマッチング演算子としてその下になります。

より堅牢にするには、次のようにします。

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

(スペースで始まる2番目の引数はexpr演算子として認識できないため、上記の問題を回避できます)。

expr $j:'.*'

これは2つの引数になります(expr$jの内容の後に:.*が続きます($jに空白文字またはワイルドカード文字が含まれていないと仮定します。以下を参照)。 exprは(コマンド名の横に)1つの引数しか認識しないため、要求される操作はありません。これは、exprがエコーバックする1つの文字列引数です。

現在、コードには他にもいくつかの問題があります。

変数の展開とコマンド置換($((...))または非推奨の`...`フォームを使用)、 引用符で囲まれていない場合はsplit+glob`cat $1`部分のsplit部分($(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
1

_expr $j:'.*'_を使用すると、コマンドexprは1つの引数を受け取ります。
コマンドexprはそれを理解できませんでした。

コマンドexprでは、各引数を明確に区切る必要があります。

_expr "$j" ":" '.*'
_

これは、コマンドexprに与えられる3つの引数になります。 _"_の前後の引用符_:_は実際には必要ありません。また、次のように誤解を避けるために、_$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以降)コンマ_,_演算子を使用し、_cc += ${#i}_を_cc = cc + ${#i}_と同等のものとして使用します。

0
user79743