文字置換を含むマップを生成するためのシェルスクリプト(例:sed)

文字置換を含むマップを生成するためのシェルスクリプト(例:sed)

"<topic>...<topic>"マッピング設定で無効な文字を置き換えてデータベーステーブル名にマッピングする必要があるトピックを表す文字列を保持するbashに変数があります。

必要なマッピング形式は次のとおりです"topic1:table1,topic2:table2"。つまり、これが私が必要とする出力です。

コンテキストでは、これは構成項目です。スノーフレークカフカコネクタこれは、トピックからテーブルにデータをストリーミングするのに役立ちます。重要なことは、許可されている文字の面でテーブル名がさらに制限されることです。

最も単純な場合、無効な文字はハイフンであり、下線に変換する必要があります。

たとえば、"foo-bar,boo-baz"入力文字列の場合、必須の答えは次のとおりです。

"foo-bar:foo_bar,boo-baz:boo_baz"

Pythonでは、次のように簡単です。

import sys
s = sys.argv[1]
print(','.join(p + ':' + p.replace('-', '_') for p in s.split(',')))

追加のソフトウェアのインストールを避けるために、シェルスクリプトツールに基づくソリューションを探しています。

たとえば、私はsedを知っていますラベルを含むこれは問題解決に役立つと思いますが、まだ解決策が見つかりませんでした。

答え1

次の変数に入力があるとしますTOPICS

使用sed:

sed 's/[^,]\+/\0:\0/g; :a s/:\([^-,]\+\)-/:\1_/g; ta' <<<"$TOPICS"
  1. s/[^,]\+/\0:\0/g- 各トピック(カンマを含まない単語)を選択し、その後に同じ単語とコロンを追加します。この部分以降の結果は次のとおりです。foo-bar:foo-bar,boo-baz:boo-baz
  2. :a s/:\([^-,]\+\)-/:\1_/g- 各コロンの後のハイフンを下線に置き換えます。
  • この時点では、各トピックの最初のハイフンのみが置き換えられます。したがって、たとえば、トピックの1つがfoo-bar-baz最初のステップの後にhasを使用している場合、foo-bar-baz:foo-bar-baz結果はこのステップの後になりますfoo-bar-baz:foo_bar-baz
  1. ta- 最近の置換が成功した場合(ハイフンはアンダースコアで置き換えられます) - タグを返して、置き換える項目がさらにあるかどうかを確認:aします。これは、トピックに複数のハイフンが含まれないようにするためです。手順2で交換が行われていない場合は、ラベルに分岐しないでください。次の行に進みます。
  • 例:foo-bar-baz:foo_bar-baz前の例は今ですfoo-bar-baz:foo_bar_baz

使用awk:

awk 'BEGIN {ORS=RS=","} { if (gsub( /\n$/, "" )) ORS="\n"; NEW=$0; gsub("-", "_", NEW); print $0":"NEW}' <<<"$TOPICS"
  1. RS(入力レコード区切り記号)とORS(出力レコード区切り記号)がに設定されます,。これにより、awk各トピックが別々の行として扱われます。
  2. if (gsub( /\n$/, "" )) ORS="\n"- 単語の最後の文字が\n(改行)の場合は削除します。gsub代替番号(1)を返し、最後の単語では、読み取った単語の後に新しい行を印刷するのではなく、最後の行(出力レコード区切り文字)としてのみ印刷します。
  3. gsub("-", "_", NEW)- ハイフンを下線に変更します。

awk++の使用:sedtr

これには追加のコマンドがありますが、読みやすくなります。

echo "$TOPICS" \
 | tr ',' '\n' \
 | awk '{NEW=$0; gsub("-", "_", NEW); print $0":"NEW}' \
 | tr '\n' ',' \
 | sed 's/,$/\n/'

  1. tr ',' '\n'- 新しい行で単語を分離することから始めましょう。
  2. awkマッピングを印刷します。
  3. tr '\n' ','- 改行をコンマに置き換えます。
  4. sed 's/,$/\n/'- 最後のカンマを除いて、ニューライン文字で置き換える必要があります。

答え2

文字列だけを操作すると仮定すると、これを達成する1つの方法は次のとおりです。

#!/usr/bin/env bash

p="foo-bar,boo-baz"
IFS=',' read -ra arr <<< "$p"
result=()

for item in "${arr[@]}"; do
  result+=("${item}:${item//-/_}")
done

end_result=$(printf '%s,' "${result[@]}")
echo "${end_result%,*}"

文字列の操作について学びたい場合は、次を参照してください。https://mywiki.wooledge.org/BashFAQ/100

答え3

すべてのUnixシステムのすべてのシェルでawkを使用してください。

$ echo 'foo-bar,boo-baz' |
    awk -F',' '{for (i=1; i<=NF; i++) {t=$i; gsub(/-/,"_",t); printf "%s:%s%s", $i, t, (i<NF ? FS : ORS)}}'
foo-bar:foo_bar,boo-baz:boo_baz

または必要に応じて:

$ echo 'foo-bar,boo-baz' |
    awk -v RS=',' '{t=$1; gsub(/-/,"_",t); printf "%s:%s%s", $1, t, (sub(/\n$/,"") ? ORS : RS)}'
foo-bar:foo_bar,boo-baz:boo_baz

入力が改行(POSIXによると、有効なテキストファイルでなければならない)で終わらないと、2番目は失敗します。

関連情報