次の値を持つファイルがあります。
猫データ.txt
server1: calv
server2: anot
log: /u/log/1
server3: calv
server4: anot
server5: secd
server6: calv
LIB_TRGT_calv,anot: /tmp/hello.txt
LIB_TRGT_secd: /var/del.tmp
LIB_TRGT
LIB_TRGT_calv,anot
ie&で始まる変数を取得します。LIB_TRGT_secd
TRGT_
上記の変数(calv、anotなど)から名前を取得する必要があります。
&を持つすべての項目をインポートして、次のようにdata.txtの項目を追加するcalv & anot
必要があります。calv
anot
希望の出力:
server1: calv
server2: anot
log: /u/log/1
server3: calv
server4: anot
server5: secd
server6: calv
LIB_TRGT_calv,anot: /tmp/hello.txt
LIB_TRGT_secd: /var/del.tmp
LIB_server1: /tmp/hello.txt
LIB_server2: /tmp/hello.txt
LIB_server3: /tmp/hello.txt
LIB_server4: /tmp/hello.txt
LIB_server6: /tmp/hello.txt
LIB_server5: /var/del.tmp
同じLIB_TRGT_secd
これまで私がしたことは次のとおりです。
grep TRGT* data.txt | cut -d: -f1 |cut -d_ -f3
calv,anot
secd
もっと遠く
grep TRGT* test.txt | cut -d: -f1 |cut -d_ -f3 | sed -n 1'p' | tr ',' '\n'
calv
anot
しかし、secd
それが欠けており、それを使用してさらに処理する方法がわかりませんxargs
。
ユーザー@Kusalanandaの解決策を試しましたが、うまくいきませんでした。以下の出力を参照してください。
答え1
この行が常に表示されるとawk
仮定し、これを実行するプログラムLIB_TRGT_
後ろに次に引用される他の行は次のとおりです。
BEGIN {
FS = ":[[:blank:]]*"
OFS = ": "
}
{ print }
$1 !~ /^LIB_TRGT_/ {
# "list" is an associative array that uses the keys "calv",
# "anot", and "secd", and for each of these stores the relevant
# servers as a SUBSEP-delimited string.
list[$2] = (list[$2] == "" ? $1 : list[$2] SUBSEP $1)
next
}
{
path = $2
# Pick out the comma-delimited list of keys after "TRGT_", and
# split these up into elements of the array "k".
sub("^.*TRGT_", "", $1)
nk = split($1, k, ",")
$0 = ""
$2 = path
# For each key, get the corresponding list from "list" and
# output the path for each of its values.
for (i = 1; i <= nk; ++i) {
nv = split(list[k[i]], v, SUBSEP)
for (j = 1; j <= nv; ++j) {
$1 = "LIB_" v[j]
print
}
}
}
script
データとともにファイル内の上記のスクリプトでテストします。Unixテキストファイルと呼ばれるfile
:
$ awk -f script file
server1: calv
server2: anot
log: /u/log/1
server3: calv
server4: anot
server5: secd
server6: calv
LIB_TRGT_calv,anot: /tmp/hello.txt
LIB_server1: /tmp/hello.txt
LIB_server3: /tmp/hello.txt
LIB_server6: /tmp/hello.txt
LIB_server2: /tmp/hello.txt
LIB_server4: /tmp/hello.txt
LIB_TRGT_secd: /var/del.tmp
LIB_server5: /var/del.tmp
順序は質問に示されているものと少し異なります。順序は、LIB_TRGT_
保存して最後に処理するのではなく、表示されるとすぐに反応するためです。
答え2
データからコードを生成し、生成されたコードをデータ自体に適用することでこの問題を解決できます。
拡張正規表現モードを使用するGNU sed。
inputf='./data.txt'
< "$inputf" \
sed -E '
s/^\s+|\s+$//g
s/\s+/\t/g
' |
sed -E '
/_TRGT_[^:\t]/{
s/^(([^_]+_)+TRGT_)([^,:]+)[,:](.*(\t\S+))$/\3\5\n\1\4/
h;s/\n.*//;s/.*\t//
s:[\/&]:\\&:g;G
s/(.*)\n(.*\t).*(\n.*)/\2\1\3/
P
}
D
' |
sed -En '
1i\
p
s#(.*)\t(.*)#/:\\t\1$/{s/^/LIB_/;s/:.*/:\\t\2/;H;ba;}#p
$a\
:a\
$!d;g;s/.//
' |
sed -Ef - "$inputf"
server1: calv
server2: anot
log: /u/log/1
server3: calv
server4: anot
server5: secd
server6: calv
LIB_TRGT_calv,anot: /tmp/hello.txt
LIB_TRGT_secd: /var/del.tmp
LIB_server1: /tmp/hello.txt
LIB_server2: /tmp/hello.txt
LIB_server3: /tmp/hello.txt
LIB_server4: /tmp/hello.txt
LIB_server5: /var/del.tmp
LIB_server6: /tmp/hello.txt
- ステップ0、先行および末尾のスペースを削除してデータをクリーンアップします。 TABに固定幅フォント。
- 最初のステップでは、キーと値のペアを分離して行ごとに1つずつ配置します。
- ステップ2これらのkvタプルを使用してsedコードを生成します。
- ステップ3、データにコードを適用します。
答え3
以下は、2つのケース、つまり2番目のフィールドが参照されるかどうかの統合ソリューションです。
awk -v q=\' '1
NF<2{next}
!/^([^_]+_)+TRGT_/ {
a[FNR] = $2
b[FNR,$2] = $1
if (index($2,q) == 1) quoted++
next
}
{
n = split($1, temp, /[_,:]/)
s=0
for (i=1; i<n; i++) {
t = temp[i]
s += length(t)+1
ch = substr($1, s-1, 1)
if (ch == "_") continue
key = (!quoted) ? t : q t q
c[key] = $2
}
split("", temp, ":")
}
BEGIN { OFS="\t" }
END {
for (i=1; i in a; i++)
if ( (a[i] in c) && ((i SUBSEP a[i]) in b))
print "LIB_"b[i,a[i]], c[a[i]]
}' data.txt
server1: 'calv'
server2: 'anot'
log: '/u/log/1'
server3: 'calv'
server4: 'anot'
server5: 'secd'
server6: 'calv'
LIB_TRGT_calv,anot: '/tmp/hello.txt'
LIB_TRGT_secd: '/var/del.tmp'
LIB_server1: '/tmp/hello.txt'
LIB_server2: '/tmp/hello.txt'
LIB_server3: '/tmp/hello.txt'
LIB_server4: '/tmp/hello.txt'
LIB_server5: '/var/del.tmp'
LIB_server6: '/tmp/hello.txt'