web-dev-qa-db-ja.com

行から特定のフィールドを削除する

ファイルに次の行があります。

Modified folders: html/project1/old/dev/vendor/symfony/yaml/Tests/bla.yml
Modified folders: html/port5/.DS_Store
Modified folders: html/trap/dev8/.DS_Store
Modified folders: html/bla3/test/appl/.DS_Store
Modified folders: html/bla4/pro1/app/bla/Api2.php
Modified folders: html/bla10/dev/appl/language/.DS_Store
Modified folders: html/bla11/dev/appl/language/abc.txt

これは基本的にrsyncの出力です。次のように、ファイルのすべての行を3つのディレクトリの場所までリストしたいと思います。

Modified folders: html/project1/old
Modified folders: html/port5
Modified folders: html/trap/dev8
Modified folders: html/bla3/test
Modified folders: html/bla4/pro1
Modified folders: html/bla10/dev
Modified folders: html/bla11/dev

誰でも私に同じことをするコマンドまたはシェルスクリプトを提供できますか?

2
john deo

たぶんこのように:

$ sed -r 's|/[^/]*$||' file | sed -r 's|([^/]*/?[^/]*/?[^/]*).*|\1|'
Modified folders: html/project1/old
Modified folders: html/port5
Modified folders: html/trap/dev8
Modified folders: html/bla3/test
Modified folders: html/bla4/pro1
Modified folders: html/bla10/dev
Modified folders: html/bla11/dev

または、cutを使用して2番目の部分を実行できます。

sed -r 's|/[^/]*$||' file | cut -d '/' -f 1,2,3

ノート

  • -r EREを使用
  • s|old|new|oldnewに置き換えます
  • [^/]*ではない任意の数の文字/
  • $行末
  • /? 0または1 /
  • (pattern)\1で後で参照するためにpatternを保存
  • .*任意の数の任意の文字
  • |(引用符なし)シェルパイプ-左側のコマンドの出力を右側のコマンドに渡します
  • cut -d '/'区切り文字として/を使用
  • -f 1,2,3最初の3つのフィールドを出力します
6
Zanna
grep -oP '^.*?(/.*?){0,2}(?=/)'

dark正規表現の簡単な説明:

  • ^... i行の始まり
  • .*?シーケンス。事前パスに一致する文字数(ただし必要な量)
  • /.*?){0,2} 0、1、または2つのディレクトリ
  • (?=/)先読み式-/含まれない
3
user216043

次のスクリプトは、(ほぼ)あなたが尋ねるとおりに行います。

#!/usr/bin/env Perl

use strict;
use warnings;

while(<DATA>) {
    s!^(Modified\s+folders:\s+)((?:[^/]+/){1,3}).*?$!$1$2!;
    print;
}

__DATA__
Modified folders: html/project1/old/dev/vendor/symfony/yaml/Tests/bla.yml
Modified folders: html/port5/.DS_Store
Modified folders: html/trap/dev8/.DS_Store
Modified folders: html/bla3/test/appl/.DS_Store
Modified folders: html/bla4/pro1/app/bla/Api2.php
Modified folders: html/bla10/dev/appl/language/.DS_Store
Modified folders: html/bla11/dev/appl/language/abc.txt

すべての入力行を読み取り、そこからいくつかの値を選択し(正規表現の手段)、選択した値で行を置き換え、最後に変更された行を(STDOUTに)出力します。

出力

Modified folders: html/project1/old/
Modified folders: html/port5/
Modified folders: html/trap/dev8/
Modified folders: html/bla3/test/
Modified folders: html/bla4/pro1/
Modified folders: html/bla10/dev/
Modified folders: html/bla11/dev/

正規表現を1行で記述する場合:

s!^(Modified\s+folders:\s+)((?:[^/]+/){1,3}).*?$!$1$2!;

それは少し怖いですが、実際には非常に簡単です。基本的な演算子は、Perlの substitution operators/// です。

s/foo/bar/;

fooのすべての出現をbarに置き換えます。 sを使用すると、区切り文字を/から別のものに変更できます。ここで!を使用したので、次のように書くこともできます

s!foo!bar!;

!は、notnotを意味しますが、ここでは単なる任意の文字です。 sLfooLbarL;も機能します。これは、標準の/を使用する場合、パラメーター内で/をエスケープする必要があるためです(これは、つまようじ構文として知られています)。パス/old/path/new/pathに置き換えることを検討してください。今比較してください:

s/\/old\/path/\/new\/path/; # escaping of / needed
s!/old/path!/new/path!;     # no escaping of / needed (but of ! if we had one in the text)

x修飾子をs///に適用することもできます。 pattern(左側)内の任意の空白(改行やコメントも)を許可して、可読性を向上させます。これで、ループは次のように記述できます。

while(<DATA>) {
    s!^                         # match beginning of line
      (Modified\s+folders:\s+)  # the Word "Modified", followed by 1 ore more 
                                # whitespace \s+,
                                # the literal "folders:", also followed by 1 or 
                                # more whitespace.
                                # We capture that match in $1 (that's why we have 
                                # parens around it).
      (                         # begin of 2nd capture group (in $2)
        (?:                     #   begin a group that is NOT captured (because of the "?:"
         [^/]+/                 #   one or more characters that are not a slash followed by a slash
        )                       #   end of group
        {1,3}                   #   this group should appear one to three times
      )                         # close capture group $2, i.e. remember the 1-3x slash thing
      .*?$                      # followed by arbitrary characters up to the end of line
     !$1$2!x;                   # Replace the line with the two found captures $1 and $2, i.e.
                                # with the text "Modified folders:" and the 1-3x slash thing.
    print;
}

完全な「スクリプト」は、ワンライナーとして記述することもできます。

Perl -pe 's!^(Modified\s+folders:\s+)((?:[^/]+/){1,3}).*?$!$1$2!x;' file

更新

Modified folders:文字列もパスのコンポーネントとして見ることができることに気付きました。そのため、パターンは

Perl -pe 's!^((?:[^/]+/){1,3}).*?$!$1!;' file
3
PerlDuck