行が非常に長くて読みやすいように、プレーンテキストの1行に4文字ごとにスペースを挿入したいと思います。最も簡単な方法は何ですか?また、パイプからラインを入力する必要があります。例えば
echo "foobarbazblargblurg" | <some command here>
与えられた
foob arba zbla rgbl urg
答え1
sedを次のように使用してください。
$ echo "foobarbazblargblurg" | sed 's/.\{4\}/& /g'
foob arba zbla rgbl urg
答え2
次の簡単な例を使用できます。
$ echo "foobarbazblargblurg" | fold -w4 | paste -sd' ' -
foob arba zbla rgbl
答え3
Bashにのみ外部コマンドはありません。
str="foobarbazblargblurg"
[[ $str =~ ${str//?/(.)} ]]
printf "%s%s%s%s " "${BASH_REMATCH[@]:1}"
または1行のパイプラインバージョンとして:
echo foobarbazblargblurg |
{ IFS= read -r str; [[ $str =~ ${str//?/(.)} ]]; \
printf "%s%s%s%s " "${BASH_REMATCH[@]:1}"; }
仕組みは、正規表現マッチングのために文字列の各文字を「(。)」に変換してを使用してキャプチャし、必要に応じてグループ化して=~
配列からキャプチャされた式を出力することです BASH_REMATCH[]
。先行/末尾/中間スペースを保持し、"${BASH_REMATCH[@]:1}"
省略するには、二重引用符を削除します。
ここでは、引数を処理するか、引数がない場合はstdinを読み取る関数でラップします。
function fmt4() {
while IFS= read -r str; do
[[ $str =~ ${str//?/(.)} ]]
printf "%s%s%s%s " "${BASH_REMATCH[@]:1}"
done < <( (( $# )) && printf '%s\n' "$@" || printf '%s\n' $(< /dev/stdin) )
}
$ echo foobarbazblargblurg | fmt4
foob arba zbla rgbl urg
カウントを簡単にパラメータ化して、フォーマット文字列を適切に調整できます。
後ろにスペースを追加し、printf
これが問題の場合は、1つの代わりに2つを使用してください。
printf "%s%s%s%s" "${BASH_REMATCH[@]:1:4}"
(( ${#BASH_REMATCH[@]} > 5 )) && printf " %s%s%s%s" "${BASH_REMATCH[@]:5}"
最初printf
は最初の4文字まで印刷し、2番目はグループを区切る先行スペースを使用して、残りのすべての文字(存在する場合)を条件付きで印刷します。テストでは、4つの要素の代わりに5つの要素について0番目の要素を説明します。
メモ:
- 代わりに、シェルを使用して意図をより明確にすること
printf
ができますが、マルチバイト文字から安全ではありません。上記は、bashバージョンがサポートしている場合はマルチバイト文字から安全です。%c
%s
%c
- シェルは
printf
引数が不足するまで書式文字列を再利用するため、一度に4つの引数のみを使用して後続の引数を処理します。したがって、ここの他の答えのいくつかとは異なり、エッジケースは必要ありません。これはおそらく間違っているでしょう。 BASH_REMATCH[0]
は一致する完全な文字列なので、インデックス1から始まる文字列のみが出力されます。printf -v myvar ...
変数に保存する代わりに使用するmyvar
(通常の読み取りループ/サブシェルの動作によって異なります)printf "\n"
必要に応じて追加
zsh
match[]
代わりに配列を使用し、一致中にゼロ個の要素が保持されないため、BASH_REMATCH[]
すべてのインデックスから1を引くと、上記の操作が正しく機能するようになります。zsh
答え4
grep
以下はsumを使った例ですxargs
。
$ echo "foobarbazblargblurg" | grep -o .... | xargs
foob arba zbla rgbl