パターンの後ではない行のgrep

Aug 17 2020

特定のパターンの後にないファイルのすべての行を見つけようとしています。

しばらくの間、historyGNU bash(バージョン4および5)の使用に問題があり、コマンドが重複して表示されていました。これは、私の.bashrc中に次の行があったためだと思いました。

 PROMPT_COMMAND="history -a; history -n; $PROMPT_COMMAND"

ターミナルマルチプレクサ(screenおよび/またはtmux)を使用しているため、上記のコマンドが数回実行されます(したがってecho $PROMPT_COMMANDhistory -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ますか?そうでない場合:どのように私は(他のツールでこれを達成することができsedawk...、)?

回答

ilkkachu Aug 17 2020 at 03:48

私が理解している限り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つだけを印刷するように機能する必要があります。

jubilatious1 Aug 17 2020 at 18:40

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つの連続したターゲット行が出力に表示されることですが、明確ではありません入力ファイルにそのような連続した行が含まれる場合は、私に]。

https://raku.org/