BashスクリプトからXMLタグ値の一部を抽出する方法

BashスクリプトからXMLタグ値の一部を抽出する方法

次のXMLファイルがあります(A.xml)。

<?xml version="1.0"?>
<RunParameters xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <RunParametersVersion>NextSeq_4_0_0</RunParametersVersion>
  <ReagentKitSerialWasEnteredInBaseSpace>false</ReagentKitSerialWasEnteredInBaseSpace>
  <ExperimentName>210913-RUN61-COCO</ExperimentName>
  <PurgeConsumables>false</PurgeConsumables>
  <MaxCyclesSupportedByReagentKit>92</MaxCyclesSupportedByReagentKit>
  <ModuleName />
  <ModuleVersion />
</RunParameters>

RUN61XMLタグポートを含むbash変数を設定したいと思います<ExperimentName>210913-RUN61-COCO</ExperimentName>。タグ値は常に次のような構造を持ちます。

重要ではない -関連-関係ない

ダッシュで区切ってください。

grep私は良い結果なしで試しました。

runNumber=$(grep -o '<ExperimentName>.*</ExperimentName>' | cut -d '-' -f2 A.xml)

何をすべきか知っていますか?

答え1

構造化データを扱うため、専用パーサーを使用する必要があります。たとえば、次のxmlstarletタグ値を抽出する必要がありますcut

xmlstarlet sel -t -c "string(/RunParameters/ExperimentName)" A.xml | cut -d- -f 2

だから、あなたは使用することができます

runNumber=$(xmlstarlet sel -t -c "string(/RunParameters/ExperimentName)" A.xml | cut -d- -f 2)

答え2

以下のみを使用してくださいxmlstarlet

experiment_name=$(
    xmlstarlet sel -t \
        -m '/RunParameters/ExperimentName' \
        -v 'substring-before(substring-after(., "-"), "-")' file.xml
)

これは、関心のあるノードと一致し、2つの関数を使用してsubstring-after()そのノード値の中間部分を削除しますsubsring-before()

次に、xmlstarlet出力を変数に割り当てますexperiment_name

または以下xqで使用してください。https://kislyuk.github.io/yq/

experiment_name=$(
    xq -r '.RunParameters.ExperimentName | split("-")[1]' file.xml
)

これはノードの値をダッシュ​​に分割し、結果の配列の2番目の要素を返します。

答え3

Raku(以前のPerl_6)の使用

raku -MXML -e 'for open-xml($*ARGFILES) {.elements(:TAG<ExperimentName>)>>.contents.put};' < input.xml

入力例:

<?xml version="1.0"?>
<RunParameters xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <RunParametersVersion>NextSeq_4_0_0</RunParametersVersion>
  <ReagentKitSerialWasEnteredInBaseSpace>false</ReagentKitSerialWasEnteredInBaseSpace>
  <ExperimentName>210913-RUN61-COCO</ExperimentName>
  <PurgeConsumables>false</PurgeConsumables>
  <MaxCyclesSupportedByReagentKit>92</MaxCyclesSupportedByReagentKit>
  <ModuleName />
  <ModuleVersion />
</RunParameters>

出力例:

210913-RUN61-COCO

他の人が述べたように、このタスクには専用のXMLパーサーを使用することをお勧めします。簡単に言えば、上記のコードでは、Rakuはbashコマンドラインから呼び出され、そのコマンドを使用して-Mモジュールをロードします。上記のコードはシェルリダイレクトに依存しています(リダイレクトなしで入力を文字列化する必要があります)。 XMLファイルを使用して必要なコンテンツを開き、照会、抽出、および返すために使用します。XML-MXML<open-xml()$*ARGFILES.Stropen-xmlTAGcontentsput

実際、OPは出力部分をcut抽出するための非常に良いコードを提供し、上記のRakuソリューションはOPのコードを通して簡単にパイプすることができます。ただし、Rakuソリューション全体の場合は、RUN61上記のRakuコードに.split("-")[1]呼び出し.containsを挿入するだけです。.put

raku -MXML -e 'for open-xml($*ARGFILES.Str) {.elements(:TAG<ExperimentName>)>>.contents.split("-")[1].put};'

https://github.com/raku-community-modules/XML
https://www.raku.org

答え4

次のように名前を抽出することもできますgrep(オプションで-E拡張正規表現を許可)。

runNumber=$(grep -Eo '[[:alnum:]]+-[[:alnum:]]+' A.xml | cut -d- -f2)

そのラベルの行を確認するには、grep別のコマンドで事前フィルタリングできます。

runNumber=$(
  grep '<ExperimentName>' A.xml \
  | grep -Eo '[[:alnum:]]+-[[:alnum:]]+' \
  | cut -d- -f2
)

メモ:

XPath式に基づくソリューション:

  • 読みやすさ
  • フォールトトレランスが高い場合があります
  • しかし、いくつかの追加の依存関係を導入できます。

関連情報