10

先週の金曜日、テキストを別の形式に変換するという問題が発生しました。そのマシンでは、gnu sed のみが使用可能で、awk はありません (奇妙なことです)。そして、私はperlについて何も知りません。だから私はsedのみの解決策を探しています。

ファイルの内容は次のとおりです。

a  yao.com sina.com
b  kongu.com
c  polm.com unee.net 21cn.com iop.com foo.com bar.com baz.net happy2all.com
d  kinge.net

必要な出力 (新しいファイルである必要があります) は次のとおりです。

a  yao.com 
a  sina.com
b  kongu.com
c  polm.com 
c  unee.net 
c  21cn.com 
c  iop.com
c  foo.com
c  bar.com
c  baz.net
c  happy2all.com
d  kinge.net

私はたくさん試し、有名な sed oneliner も検索しましたが、うまくいきません...誰か助けてくれますか?

4

8 に答える 8

6

興味深い問題:

$ sed -r 's/(\w+\.\w+)/>  &/2g;:a s/^([a-z]+)(.*)>/\1\2\n\1/g;ta' file
a  yao.com 
a  sina.com
b  kongu.com
c  polm.com 
c  unee.net 
c  21cn.com 
c  iop.com 
c  foo.com 
c  bar.com 
c  baz.net 
c  happy2all.com
d  kinge.net

編集:

2 つの置換を使用して動作します。

>1 つ目は、保持文字として平坦化が必要な URL の前に a を置きます。

$ sed -r 's/(\w+\.\w+)/>  &/2g' file
a  yao.com >  sina.com
b  kongu.com
c  polm.com >  unee.net >  21cn.com >  iop.com >  foo.com >  bar.com ...
d  kinge.net

2番目は基本的に保持>を改行に置き換えます(条件分岐を使用します)

$ sed -r ':a s/^([a-z]+)(.*)>/\1\2\n\1/g;ta'
于 2013-03-16T22:09:40.293 に答える
5

sed、特にワンライナーにとっては簡単な仕事ではありません。ただし、「gnu sed」について言及しました。私は光を見ます!

gnu sed はs/.../.../ge、この状況に役立つものをサポートしています:

kent$  sed -r 's@(^[a-z]+) (.*)@echo "\2"\|sed "s# #\\n\1  #g"\|sed "/^$/d"@ge' file  
a  yao.com
a  sina.com
b  kongu.com
c  polm.com
c  unee.net
c  21cn.com
c  iop.com
c  foo.com
c  bar.com
c  baz.net
c  happy2all.com
d  kinge.net

簡単な説明:

  1. 外側の sed はsed -r 's@..x..@..y..@ge' filege一致した部分を外部コマンドに渡すことを可能にします
  2. その..y..部分は の魔法によって行われgeます。私は(経由で)\2別のものに渡します:このsedはすべてのスペースをsedechosed "s# #\\n\1 #g"\n + \1 + space
  3. 元のファイルでは\n、各行 (末尾) にあるため、ステップ 2 (上記のステップ) の結果に空の行があるため、それらの空の行を削除する必要があります。"/^$/d"
  4. 最後に、ステップ 1 の置換 (外側の sed) が実行され、結果が得られます。

を確認info sedしてくださいs/../../ge

編集、OPがコメントしたように二重スペースを追加しました。

于 2013-03-16T22:20:50.410 に答える
1

これが機能する真のsed専用スクリプトです。以下に、コマンドラインでsedによって呼び出されるファイルとして記述しましたが、すべてコマンドラインで入力することも、別のスクリプトに入力することもできます。

以下をsedscript(またはあなたがそれを呼びたいもの)として保存します。出力の後に説明が続きます。

:start
    h
    s/\(.\ \ [^ ]*\).*/\1/
    t continue
    d
:continue
    p
    x
    s/\(.\ \)\ [^ ]*\(\ .*\)/\1\2/
    t start
    d

今すぐ実行sed -f sedscript myfile.txt

上記の例をmyfile.txtとして保存すると、次のように出力されます。

a  yao.com
a  sina.com
b  kongu.com
c  polm.com
c  unee.net
c  21cn.com
c  iop.com
c  foo.com
c  bar.com
c  baz.net
c  happy2all.com
d  kinge.net

Sedには、パターンバッファー(通常はs/a/b/ある種のコマンドを操作する場所)とホールドバッファーがあります。このスクリプトでは、情報がホールドバッファーと前後に交換され、別の部分で作業している間、行の編集されていない部分が保持されます。

:start=ジャンプを有効にするラベル

h=パターンバッファ(現在の行)をホールドバッファにスワップします

s/\(.\ \ [^ ]*\).*/\1/=ホールドバッファ内のフルラインは安全ですが、最初のドメイン以降のすべてを削除し、最初の目的のラインを残します(例:「ayao.com」)。

t continue=前のコマンドで置換が行われた場合は、「続行」ラベルにジャンプします

d=ジャンプしなかった場合、それは完了したことを意味します。パターンバッファを削除し、ファイルの次の行に進みます。

:continue=前のジャンプのラベル

p=パターンバッファを出力します(例:「ayao.com」)

x=パターンバッファーをホールドバッファーと交換します(ホールドバッファーgをパターンバッファーにコピーするために使用することもできます)

s/\(.\ \)\ [^ ]*\(\ .*\)/\1\2/=元の文字列全体がパターンバッファにスワップされました-処理したドメインを削除します(例: "yao.com")

t start=それが最後のドメインではなかった場合は、新しい短縮された文字列でスクリプトを最初からやり直してください。

d=それが最後のドメインである場合は、パターンバッファーを削除し、ファイルの次の行に進みます。

于 2013-03-16T23:56:54.313 に答える
1

これはうまくいくかもしれません(GNU sed):

sed -r 's/^((\S+\s+)\S+)\s+/\1\n\2/;P;D' file
于 2013-03-17T14:01:00.753 に答える
1

他の人が指摘したように、sed ソリューションはトリッキーなので、bash-dito を投稿すると思いました:

#!/bin/bash

while read -a array
do
    for i in ${array[@]:1}
    do
        echo ${array[0]} $i
    done
done < input

出力:

a yao.com
a sina.com
b kongu.com
c polm.com
c unee.net
c 21cn.com
c iop.com
c foo.com
c bar.com
c baz.net
c happy2all.com
d kinge.net
于 2013-03-16T22:32:12.347 に答える
0
cat inputFile.txt | sed -e 's/\([^\ ]*\)\(\ *\)\([^\ ]*\)\(\ *\)\([^\ ]*\)\(\ *\)\([^\ ]*\)\(\ *\)\([^\ ]*\)\(\ *\)/\1 \3\n\1 \5\n\1 \7\n\1 \9/' | grep -vE "^..$"

私のUbuntu 12.10で動作します。

説明:

  • テキストを含むグループと空の文字を含むグループの 2 つのグループに分割します。
  • グループ 1 (最初の文字を含む) と偶数グループ (テキストを含む) を繰り返します
  • 現在、空の文字で区切られた 4 つのテキストで機能します

最後に、空の「2 番目」のグループを含む行を削除します。

BASH で別の試行 (「script.sh inputFile.txt」として実行):

#!/bin/bash

firstParams=`cat $1 | sed -e 's/\([^\ ]*\)\(.*\)/\1/'`
count=1
for MY1 in $firstParams
do
    # print line number ${count} and filter params from the second one forth
    restParams=`cat $1 | sed -n "${count}p" | sed -e 's/\([^\ ]*\)\(.*\)/\2/'`
    for MY2 in $restParams
    do
        echo "$MY1 $MY2"
    done
    count=$(($count+1))
done
于 2013-03-16T21:38:50.240 に答える
-1

使用できます

sed -r -n 's/^([a-z])\ \ ([0-9a-z.]*)\ ([0-9a-z .]*)/\1  \2\n\1  \3/p'

フォームの各行を変換します

c  polm.com unee.net 21cn.com iop.com foo.com bar.com baz.net happy2all.com

の中へ

c  polm.com
c  unee.net 21cn.com iop.com foo.com bar.com baz.net happy2all.com

実行されるたびに。

したがって、次に前の sed の出力で実行されると、これは次のようになります

c  polm.com
c  unee.net
c  21cn.com iop.com foo.com bar.com baz.net happy2all.com

等々。

したがって、以前の sed の出力を新しい sed にプッシュすると、最終的に必要な形式が得られます。

これがおそらく最適な答えではないことはわかっています。可能であれば、それを改善しようとします。

于 2013-03-16T22:10:37.280 に答える