📘

[zsh]ファイルの中身をn文字区切りで改行して表示

2022/01/23に公開

方法が知りたい方

オチに進んでください。

考えたコード

掲題の件、実現したく、シェルスクリプトを考えてみた。

細けぇ解説(1行目)

f=a.txt;c=30;

繰り返し書くのがだるいので、変数fに対象のファイル名、変数cに区切りたい文字数を入れます。

for i in {0..$(wc -c<$f|bc)..$c}

for文に噛ませる数字を出力する方法として、zshのブレース展開(brace expansion)を使ってます。
左に開始の数、真ん中に終了の数、右に増やす数を書きます。
例えば、echo {1..9..2}とすると、1 3 5 7 9と表示されます。
今回の処理では0からファイルの文字数(バイト数)までの数字を、cずつ増やして出力としています。
なお、Pythonのrange(range(1,9,2))なんかだと終了の数は含まれない(1 3 5 7になる)ですが、ブレース展開は含まれる点に注意が必要です。

wc -c<$f|bc

$fに設定されているファイルをリダイレクション(redirection)で、読み込み、wcに渡しています。
wcの引数に普通にファイル渡せばええやん!と思うかもしれませんが、リダイレクション時は標準入力からのデータ注入になるので、ファイル名が表示されなくなるんです。(多分wcは第一引数をファイル名として表示する仕様なんじゃないかなと...)
つまり、echo "hogeee" | wc -cと同じような挙動になります。
ブレース展開に噛ませるときにファイル名は余計な情報なのでこうしてます。

ただ、これだけではブレース展開に噛ませることは出来ないんです。何故ならwcの出力結果は最初の方にスペースが入ってしまうから。
そこで、bcに送ることによって、数字だけを表示するようにしています。
bcは本来、計算に使うコマンドですが、スペース込みの数字を送っても、いい感じに数字だけをパースしてくれるようです。

wc -c $f | awk '{ print $1 }'でいいじゃないかという声が聞こえてきそうですが、文字数が少ない方が楽なので!
(というと、なんでコマンド置換(command substitution)にbackticks使わないんだという話になりそうですが、この辺の理由です。)

細けぇ解説(3行目)

cut -c$((i+1))-$((i+$c))<$f

cut -cでi+1バイト目からi+cバイト目までを切り抜いて表示します。
$(())はzshで計算するときの記法です。

オチ

久々にシェルスクリプト考えたわーこれなら完璧だわーと思った時期が俺にもありました。
先人とは偉大なもので、foldコマンドなるものがあった...。

fold -w 30 a.txt

ワイの時間返して...。

Discussion