bash readを使用して文字単位で読み取る

bash readを使用して文字単位で読み取る

私はbashを使用して文字ごとにファイルを読み取ろうとしました。

多くの試行錯誤の後、私はこれがうまくいくことがわかりました。

exec 4<file.txt 
declare -i n
while read -r ch <&4; 
     n=0
     while [ ! $n -eq ${#ch} ]
           do  echo -n "${ch:$n:1}"
               (( n++ ))
          done
     echo "" 
     done

つまり、1行ずつ読み取ることができ、各行を文字ごとに繰り返すことができます。

これを行う前に、次のことを試しました。 exec 4<file.txt && while read -r -n1 ch <&4; do; echo -n "$ch"; done しかし、そうです。ファイル内のすべてのスペースをスキップする

理由を説明できますか? 2番目の戦略(つまり、bash読み取りを使用して文字ごとに読み取り)を操作する方法はありますか?

ベストアンサー1

先行文字と末尾文字のスキップを停止する$IFSには、引数から空白文字を削除する必要があります(使用する場合は、空白文字(存在する場合)が先行文字と末尾文字になるためスキップします)。read-n1

while IFS= read -rn1 a; do printf %s "$a"; done

しかし、そのような場合でもbashはread改行をスキップするので、次のように問題を解決できます。

while IFS= read -rn1 a; do printf %s "${a:-$'\n'}"; done

IFS= read -d '' -rn1これは単一の文字を読み取るコマンドですが、代替コマンドまたはより良いコマンドIFS= read -N1(4.1に追加、コピーksh93o追加))を使用することもできます。

BashはreadNUL文字を処理できません。 ksh93にもbashと同じ問題があります。

zshを使う:

while read -ku0 a; do print -rn -- "$a"; done

(zshはNUL文字を処理できます)。

read -k/n/N読んでみてください。数値、いいえバイト。したがって、マルチバイト文字の場合は、文字全体を読み込むまで複数バイトを読み取る必要があります。入力に無効な文字が含まれていると、有効な文字を形成しないバイト列を含む変数が生成され、シェルはそれを複数の文字として計算することができます。数値。たとえば、UTF-8ロケールでは次のようになります。

$ printf '\375\200\200\200\200ABC' | bash -c '
    IFS= read  -rN1 a; echo "${#a}"'
6

これにより、\3756バイトのUTF-8文字が導入されます。ただし、上記の6番目(A)はUTF-8文字には無効です。それでも\375\200\200\200\200Ainで終わり、$aこれはbash6として計算されます。数値最初の5つは実際の文字ではありませんが、5バイトに過ぎず、文字の一部を構成しません。

おすすめ記事