私は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に追加、コピーksh93
(o
追加))を使用することもできます。
Bashはread
NUL文字を処理できません。 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
これにより、\375
6バイトのUTF-8文字が導入されます。ただし、上記の6番目(A
)はUTF-8文字には無効です。それでも\375\200\200\200\200A
inで終わり、$a
これはbash
6として計算されます。数値最初の5つは実際の文字ではありませんが、5バイトに過ぎず、文字の一部を構成しません。
答え2
cut
以下はfor
、loop& を使った簡単な例ですwc
。
bytes=$(wc -c < /etc/passwd)
file=$(</etc/passwd)
for ((i=0; i<bytes; i++)); do
echo $file | cut -c $i
done
キスいいえ?