ファイルに次の行があります。
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
誰でも私に同じことをするコマンドまたはシェルスクリプトを提供できますか?
たぶんこのように:
$ 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|
old
をnew
に置き換えます[^/]*
ではない任意の数の文字/
$
行末/?
0または1 /
(pattern)
\1
で後で参照するためにpattern
を保存.*
任意の数の任意の文字|
(引用符なし)シェルパイプ-左側のコマンドの出力を右側のコマンドに渡しますcut -d '/'
区切り文字として/
を使用-f 1,2,3
最初の3つのフィールドを出力しますgrep -oP '^.*?(/.*?){0,2}(?=/)'
dark正規表現の簡単な説明:
^...
i行の始まり.*?
シーケンス。事前パスに一致する文字数(ただし必要な量)/.*?){0,2}
0、1、または2つのディレクトリ(?=/)
先読み式-/
含まれない次のスクリプトは、(ほぼ)あなたが尋ねるとおりに行います。
#!/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!;
!
は、notはnot
を意味しますが、ここでは単なる任意の文字です。 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