パターンの後ではない行のgrep
特定のパターンの後にないファイルのすべての行を見つけようとしています。
しばらくの間、history
GNU bash
(バージョン4および5)の使用に問題があり、コマンドが重複して表示されていました。これは、私の.bashrc
中に次の行があったためだと思いました。
PROMPT_COMMAND="history -a; history -n; $PROMPT_COMMAND"
ターミナルマルチプレクサ(screen
および/またはtmux
)を使用しているため、上記のコマンドが数回実行されます(したがってecho $PROMPT_COMMAND
、history -a; history -n; history -a; history -n;
状況によっては(特に、異なるペイン/ウィンドウ/フレーム/バッファーで同時に作業を行う場合)、最後に入力したコマンドが2回またはそれ以上の頻度でに保存されていました~/.bash_history
。これにより、次のようなエントリが作成されました。
#1596110297
yadm list -a | xargs -t ls -l
yadm list -a | xargs -t ls -l
言うまでもなく、これはかなり面倒です。 私は(うまくいけば) 修正:これはhistory
-issueの修正を(コマンドをに変更することで)見つけましたPROMPT_COMMAND="history -a; history -n
が、history
。の重複したエントリの問題を解決しませんでした。
ここで、重複したエントリを削除したいと思います。
したがって、私は現在、最初の#
行とその後の1行を除くすべてをマークする正規表現を見つけようとしています。私の最初のアイデアは、grep -v
(選択を反転するために)とgrep -A 1
(一致するパターンの後にさらに1行を取得するために)結合することでした。だが
grep -v "^#" -A 1 ~/.bash_history
期待した結果が得られませんでした。
したがって、私の質問:誰かがそれを使用してそれを行う方法について良いアイデアを持っていgrep
ますか?そうでない場合:どのように私は(他のツールでこれを達成することができsed
、awk
...、)?
回答
私が理解している限りgrep -v "^#" -A 1
では、ハッシュ記号で始まらない行を1行ずつ印刷することを意味します。しかし、あなたは反対のことをしたくない、ライン印刷ん後にハッシュ記号で始まり、1行を?
与えられたテストファイル:
#123
echo this
echo this
#456
echo that
echo that
echo that
#789
echo third
grep -A1 ^# history.txt |grep -vxFe --
プリント:
#123
echo this
#456
echo that
#789
echo third
2つ目grep
は、グループ区切り文字のgrep -A
印刷を削除することです。
あるいはuniq history.txt
、連続する同一の行の各セットの1つだけを印刷するように機能する必要があります。
Raku(旧姓Perl6)を使用
これは、多くのスクリプト言語で利用できる「フリップフロップ」オペレーターの仕事のようです。以下は、Rakuプログラミング言語(以前はPerl6と呼ばれていました)を使用した回答です。まず、より広範なテストファイルを作成することから始めます。
$ cat repeated_log.txt
#1596110297_1
A_yadm list -a | xargs -t ls -l
B_yadm list -a | xargs -t ls -l
#1596110297_2
C_yadm list -a | xargs -t ls -l
D_yadm list -a | xargs -t ls -l
E_yadm list -a | xargs -t ls -l
#1596110297_3
F_yadm list -a | xargs -t ls -l
G_yadm list -a | xargs -t ls -l
H_yadm list -a | xargs -t ls -l
I_yadm list -a | xargs -t ls -l
#1596110297_4
#1596110297_5
ここで、fff
「sedのような」動作を実装するRakuのフリップフロップ演算子を使用するワンライナーについて説明します。最初の正規表現で(行の先頭に^^
)リテラルの「#」文字が表示される行では、キャプチャがオンになります。オンになると、キャプチャは最初の正規表現を無視し、2番目の正規表現に対して評価し、(行の先頭で^^
)「#」文字が欠落している行との一致を検出するとオフになります。「負の」正規表現は<-[#]>
、を使用して以下のコードで実装されます。これは、負の「列挙文字クラス」であり、Raku言語の実際の機能です。
$ raku -ne '.put if /^^ "#" / fff /^^ <-[#]> /;' repeated_log.txt
#1596110297_1
A_yadm list -a | xargs -t ls -l
#1596110297_2
C_yadm list -a | xargs -t ls -l
#1596110297_3
F_yadm list -a | xargs -t ls -l
#1596110297_4
#1596110297_5
実際には、最初の正規表現(fff
中置演算子の左側)は<+[#]>
、より並列な構成のために、正の「列挙文字クラス」を使用して記述できます。
$ raku -ne '.put if /^^ <+[#]> / fff /^^ <-[#]> /;' repeated_log.txt
#1596110297_1
A_yadm list -a | xargs -t ls -l
#1596110297_2
C_yadm list -a | xargs -t ls -l
#1596110297_3
F_yadm list -a | xargs -t ls -l
#1596110297_4
#1596110297_5
また、行頭の「#」の後に1つ以上の数字が続く一致を要求することで、正規表現を改善できるようです。つまり<digit>+
、以下を参照してください。
$ raku -ne '.put if /^^ <+[#]> <digit>+ / fff /^^ <-[#]> <-digit>+ /;' repeated_log.txt
#1596110297_1
A_yadm list -a | xargs -t ls -l
#1596110297_2
C_yadm list -a | xargs -t ls -l
#1596110297_3
F_yadm list -a | xargs -t ls -l
#1596110297_4
#1596110297_5
[上記のすべてのコードは、B、D、E、G、H、およびIで始まる重複行を削除します。私が気付いた唯一の癖は、「#1596110297」のような2つの連続したターゲット行が出力に表示されることですが、明確ではありません入力ファイルにそのような連続した行が含まれる場合は、私に]。