grepを使用してLinuxシステム上のファイルからパーティションの日付/時刻を抽出するのに役立ちます。
ソースファイルは、次のデータを含むXMLです。
<item start="20231010073000 +0100" stop="20231010100000 +0100">...</item>
完全な開始日を抽出する必要がありますが、grepを使用すると完全な結果を得ることはできません。私のコード:
for startDate in $(grep -Eo 'start="[0-9]{14} [\+|\-][0-9]{4}"' "$filepath" ); do
echo "$startDate"
done
2つの異なる結果を得る。
start="20231010073000
+0100"
次のように取得できます。
start="20231010073000 +0100"
私は他の例を試しましたが、\s
同じ[[:space:]]
解決策を使用しました。
私のコードにバグがあるようですが、修正することはできません。
どんな助けでもくれてありがとう!
答え1
grep
使用またはregex
解析しないでくださいHTML/XML
生のテキスト行を処理するように設計されたツールを使用すると、構造化テキスト(XML / HTMLなど)を解析することはできず、解析することもできません。 XML/HTML を処理する必要がある場合は、XML/HTML パーサーを使用してください。ほとんどの言語にはXML解析サポートが組み込まれており、たとえばコマンドラインシェルですばやく作業を行う必要がある場合などの特殊なツールがありますxidel
。アクセスできない場合は、操作を受け入れないでください。適切なツール。xmlstarlet
xmllint
最も先進的なコマンドラインツールは次のとおりです。xidel
。構文はorよりも直感的でモダンです(XPath3
他のツールが制限されている場合もサポートXPath1
)。以下を参照してください。xmlstarlet
xmllint
xidel -e '//item/@start' -s file.xml
20231010073000 +0100
-e
XPath
e
表現に使用される-s
ilent の場合s
(状態情報なし)
クエリ言語は、XPath
XML / HTMLを解析するさまざまな状況で役立ちます。
XPath
指導時間:
https://developer.mozilla.org/en-US/docs/Web/XPath
http://www.w3schools.com/xpath/xpath_functions.asp
http://stackoverflow.com/tags/xpath/info
https://topswagcode.com/xpath/(インタラクティブXPath
ゲーム、基本が揃っていてインタラクティブに練習したいとき)
答え2
問題はループにあります。デフォルトでは分割されます$IFS
(デフォルトはランダムまたは$IFS
文字シーケンスで、最初と最後も削除します)。space
tab
newline
この問題を解決するには、次のようないくつかの方法があります。
while IFS= read -r StartDate; do
echo "$StartDate"
done < <(grep -Eo -- 'start="[0-9]{14} [+-][0-9]{4}"' "$filepath")
(オプションが有効になっていない場合は、bashシェルの場合と同様に、ループがサブシェルではなく現在のシェルになるようにするために:代わりに:loop < <( command generating the input )
型を使用します。常に必要なわけではありません。値はサブシェルの末尾から消え、現在のシェルから取得できません。command generating the input | loop
lastpipe
$StartDate
答え3
XMLを扱っているので、実際に属性値を取得するにはXMLパーサーを使用する必要があります。
start
次のコマンドを使用して文書全体のすべてのノードから属性値を取得する方法は次のとおりです。item
xmlstarlet
$ xmlstarlet select --template --value-of '//item/@start' --nl file
20231010073000 +0100
または、省略されたオプション名を使用してください。
$ xmlstarlet sel -t -v '//item/@start' -n file
20231010073000 +0100
複数のノードがあり、最初のノードの属性値のみがitem
必要な場合は、XPathクエリでこれを使用します。start
//item[1]/@start
その後、標準コマンド置換を使用して結果を変数として転送できます。
start=$( xmlstarlet sel -t -v '//item[1]/@start' file )
(-n
これ以上不要になったため、上記のコマンドからそのオプションを削除しました。出力の末尾に改行文字を追加しますが、コマンドの置き換えはそれを削除します。)
bash
または、以下を使用してすべての項目を配列として読み取ることができますreadarray
。
readarray -t startarray < <(
xmlstarlet sel -t -v '//item/@start' -n file
)
その後、(または)for start in "${startarray[@]}"; do ...; done
出力を直接繰り返します。xmlstarlet
while IFS= read -r start; do
# ...
done < <( xmlstarlet ...as above... )
答え4
XMLを正しく解析するためにシステムに追加の依存関係をインストールできない場合は、1行で実行するのではなく、解析をよりエレガントに処理するスクリプトを作成します。
以下は、あなたが提供した行からその時間を解析するサンプルスクリプトです。
#!/usr/bin/env bash
INPUT_FILE="$1"
TIME_FILTER='[0-9]*\s(\+|\-)[0-9]*'
__getStart(){
line="$1"
echo "$line" | egrep -o "start=\"${TIME_FILTER}\"" | egrep -o "$TIME_FILTER"
}
__getStop(){
line="$1"
echo "$line" | egrep -o "stop=\"${TIME_FILTER}\"" | egrep -o "$TIME_FILTER"
}
while IFS= read -r line; do
start_time="$(__getStart "$line")"
stop_time="$(__getStop "$line")"
echo "Start Time: ${start_time}"
echo "Stop Time: ${stop_time}"
done < "$INPUT_FILE"
このようにスクリプトを使用できます
[/var/tmp] $ ./get-dates.sh date-extraction.xml
Start Time: 20231010073000 +0100
Stop Time: 20231010100000 +0100