質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
bash

bash(Bourne-again-Shell)は sh(Bourne Shell)のインプリメンテーションに様々な機能が追加されたシェルです。LinuxやMac OS XではBashはデフォルトで導入されています。

シェルスクリプト

シェルスクリプトは、UNIX系のOSもしくはコマンドラインインタプリタ向けに記述されたスクリプト。bash/zshといったシェルによって実行されるため、このように呼ばれています。バッチ処理などに使用されており、テキストファイルに書かれた命令を順に実行します。

Linux

Linuxは、Unixをベースにして開発されたオペレーティングシステムです。日本では「リナックス」と呼ばれています。 主にWebサーバやDNSサーバ、イントラネットなどのサーバ用OSとして利用されています。 上位500のスーパーコンピュータの90%以上はLinuxを使用しています。 携帯端末用のプラットフォームAndroidは、Linuxカーネル上に構築されています。

Q&A

解決済

1回答

515閲覧

Bash の作業ログでバックスペースの制御文字を削除したい

退会済みユーザー

退会済みユーザー

総合スコア0

bash

bash(Bourne-again-Shell)は sh(Bourne Shell)のインプリメンテーションに様々な機能が追加されたシェルです。LinuxやMac OS XではBashはデフォルトで導入されています。

シェルスクリプト

シェルスクリプトは、UNIX系のOSもしくはコマンドラインインタプリタ向けに記述されたスクリプト。bash/zshといったシェルによって実行されるため、このように呼ばれています。バッチ処理などに使用されており、テキストファイルに書かれた命令を順に実行します。

Linux

Linuxは、Unixをベースにして開発されたオペレーティングシステムです。日本では「リナックス」と呼ばれています。 主にWebサーバやDNSサーバ、イントラネットなどのサーバ用OSとして利用されています。 上位500のスーパーコンピュータの90%以上はLinuxを使用しています。 携帯端末用のプラットフォームAndroidは、Linuxカーネル上に構築されています。

0グッド

0クリップ

投稿2023/12/16 10:29

環境は、WSL2 Ubuntu-22.04 です。
WSL で xyz と入力し、そのあと、Backspace で、xyz を消して、abc と入力します。
結果は以下のようになります。

Bash

1$ script 2Script started, output log file is 'typescript'. 3$ echo abc 4abc 5$ exit 6exit 7Script done. 8$ cat -v typescript 9Script started on 2023-12-16 15:06:46+09:00 [TERM="xterm-256color" TTY="/dev/pts/4" COLUMNS="144" LINES="18"] 10^[[?2004h^[]0;user@HostName: ~^G^[[01;32muser@HostName^[[00m:^[[01;34m~^[[00m$ echo xyz^H^[[K^H^[[K^H^[[Kabc^M 11^[[?2004l^Mabc^M 12^[[?2004h^[]0;user@HostName: ~^G^[[01;32muser@HostName^[[00m:^[[01;34m~^[[00m$ exit^M 13^[[?2004l^Mexit^M

結果は、echo xyz^H^[[K^H^[[K^H^[[Kabc^M で、xyz^H^[[K^H^[[K^H^[[K の部分を削除したいです。
WSL2 だと、^[[K が入るので、ひとまずそれらを削除して、xyx^H^H^Habc^M にしてから、col -b とすると以下の結果になります。

Bash

1$ sed $'s/\e\[K//g' typescript | col -b | cat -v 2# 不要な部分省略 3echo abc

うまくいっているように見えます。ところが、WSL だと、abc と入力し、そのあと左矢印「←」で三回カーソルを移動し、
それから右矢印「→」で三回カーソルを移動させると、次のようにログが記憶されます。
echo abc^H^H^H^[[C^[[C^[[C^M
なので、この状態で、col -b とすると、カーソルを移動しただけなのに、abc が消えてしまいます。

Bash

1$ col -b < typescript 2echo CCC

そこで、col -b を使わずに、バックスペースの制御文字と消したはずの文字列をファイルに残さずに削除したいと思っています。
バックスペースの制御文字だけ消すなら、
sed -E $'s/(\b\e\[K)+//g' typescript | cat -v でいいようですが、
バックススペースで消したはずの文字列も削除しようとするとそう簡単にはうまくいきません。
いろいろとテストしてみると、^[[K 以外のパターンが入る場合もあり、ちょっと私個人の力では手に負えない印象です。
そこで、日本語とか違うパターンとかは無視して、今回は簡略化して、^[[K が交じるパターンのみで確認したいと思っています。
例として以下のようなものです。
echo xyz^H^[[K^H^[[K^H^[[Kabc1234^H^[[K^H^[[K77^H^H^H^[[C^[[C^[[Cxy^H^[[K^H^[[Kpq^M
echo abc1277pq としたのですが、Backspace で何度か適当に削除したり、カーソル移動したりしたものがログに保存されているとします。
考え方としては、一行ずつ頭から ^H^[[K を一単位として、それが繰り返されている分だけ、その前の一文字を繰り返して消せばいいのではないか、と思っています。
なので、上の例だと、sed -E $'s/.{3}(\b\e\[K){3}//' で、xyz と制御文字を、
次にsed -E $'s/.{2}(\b\e\[K){2}//' で、34 と制御文字を、その次にsed -E s/.{2}(\b\e\[K){2}// で、xy と制御文字を消して、
最後に不要な移動カーソルの ^H^[[C を削除すればいいかと。
そのように考えて以下のように書いてみました。

Bash

1#!/bin/bash 2while read line; do 3 if [[ $line =~ $'\b\e[K' ]]; then 4 n1=$(echo "$line" | grep -oE $'(\b\e\[K)+' | grep -cE $'(\b\e\[K)+') 5 for ((i=1; i<=n1; i++)); { 6 if [[ $line =~ (($'\b\e[K')+) ]]; then 7 n2=$(echo -n ${BASH_REMATCH[1]} | sed $'s/\b\e\[K/@/g' | wc -m) 8 # 以下のコードでは、\b\e\[K ではうまくいかず、16進法で表記したらうまくいった 9 line=$(echo "$line" | sed -E $'s/.{'$n2'}(\x08\x1b\[K){'$n2'}//') 10 fi 11 } 12 echo "$line" | tr -d $'\b\e[C' 13 else 14 echo "$line" | tr -d $'\b\e[C' 15 fi 16done < typescript > test.log

結果を見ると、一応想定通りのように見えます。
この考え方やコードで間違ったところはないでしょうか?
ご存じの方いらしたらよろしくお願いします。

Bash

1$ cat -v test.log 2Script done on 2023-12-16 16:54:30+09:00 [COMMAND_EXIT_CODE="0"] 3Script started on 2023-12-16 17:41:51+09:00 [TERM="xterm-256color" TTY="/dev/pts/4" COLUMNS="144" LINES="18"] 4?2004h]0;user@HostName: ~^G01;32muser@HostName00m:01;34m~00m$ echo abc1277pq^M 5^[[?2004l^Mabc1277pq^M 6?2004h]0;user@HostName: ~^G01;32muser@HostName00m:01;34m~00m$ exit^M 7^[[?2004l^Mexit^M 8 9Script done on 2023-12-16 17:43:17+09:00 [COMMAND_EXIT_CODE="0"]

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

上の例だと、sed -E $'s/.{3}(\b\e[K){3}//' で、xyz と制御文字を、次にsed -E $'s/.{2}(\b\e[K){2}//' で、34 と制御文字を、その次にsed -E s/.{2}(\b\e[K){2}// で、xy と制御文字を消して〜

この部分は繰り返し処理(:a;s/.\b\e\[K//;ta;)にすればよいかと。

bash

1$ cat textlog | sed -E -e $':a;s/.\b\e\[K//;ta;s/\e\[C//g;s/\b//g;' | od -tx1a 20000000 65 63 68 6f 20 61 62 63 31 32 37 37 70 71 0d 0a 3 e c h o sp a b c 1 2 7 7 p q cr nl

投稿2023/12/16 12:07

編集2023/12/16 12:09
melian

総合スコア19825

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2023/12/17 01:02

なるほど、うまくいきました。ご回答ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問