理想的には、私ができることは次のとおりです。
cat xhtmlfile.xhtml |
getElementViaXPath --path='/html/head/title' |
sed -e 's%(^<title>|</title>$)%%g' > titleOfXHTMLPage.txt
理想的には、私ができることは次のとおりです。
cat xhtmlfile.xhtml |
getElementViaXPath --path='/html/head/title' |
sed -e 's%(^<title>|</title>$)%%g' > titleOfXHTMLPage.txt
回答:
これは実際にはユゼムの答えの単なる説明ですが、私はこれほど多くの編集が誰かに行われるべきだとは思いませんでした、そしてコメントはフォーマットを許可しないので...
rdom () { local IFS=\> ; read -d \< E C ;}
それを「rdom」の代わりに「read_dom」と呼び、少しスペースを空けて、より長い変数を使用します。
read_dom () {
local IFS=\>
read -d \< ENTITY CONTENT
}
それで、read_domという関数を定義します。1行目は、IFS(入力フィールド区切り文字)をこの関数に対してローカルにし、>に変更します。つまり、スペース、タブ、または改行で自動的に分割されるのではなく、データを読み取ると、「>」で分割されます。次の行は、標準入力から入力を読み取るように指示し、改行で停止する代わりに、「<」文字(デリミネーターフラグの-d)が表示されたときに停止します。読み取られたものは、IFSを使用して分割され、変数ENTITYおよびCONTENTに割り当てられます。したがって、次のことを考えてください。
<tag>value</tag>
read_dom
空の文字列を取得するための最初の呼び出し( '<'が最初の文字であるため)。「>」文字がないため、IFSによって ''に分割されます。次に、両方の変数に空の文字列を割り当てます。2番目の呼び出しは、文字列 'tag> value'を取得します。次に、IFSによって2つのフィールド「タグ」と「値」に分割されます。読むには、その後のような変数を割り当てますENTITY=tag
とCONTENT=value
。3番目の呼び出しは、文字列「/ tag>」を取得します。これは、IFSによって2つのフィールド '/ tag'と ''に分割されます。読むには、その後のような変数を割り当てますENTITY=/tag
とCONTENT=
。ファイルの終わりに達したため、4番目の呼び出しはゼロ以外のステータスを返します。
これで、彼のwhileループが上記に一致するように少しクリーンアップされました。
while read_dom; do
if [[ $ENTITY = "title" ]]; then
echo $CONTENT
exit
fi
done < xhtmlfile.xhtml > titleOfXHTMLPage.txt
最初の行は、「read_dom関数がゼロのステータスを返す間、次のことを行います」とだけ言っています。2行目では、今見たエンティティが「タイトル」であるかどうかを確認しています。次の行はタグの内容をエコーします。4つの行が終了します。タイトルエンティティでない場合、ループは6行目で繰り返されます。「xhtmlfile.xhtml」を標準入力(read_dom
関数の場合)にリダイレクトし、標準出力を「titleOfXHTMLPage.txt」(ループの前半からのエコー)にリダイレクトします。
次に、(S3にバケットをリストすることで得られるものと同様に)以下を指定しますinput.xml
。
<ListBucketResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<Name>sth-items</Name>
<IsTruncated>false</IsTruncated>
<Contents>
<Key>item-apple-iso@2x.png</Key>
<LastModified>2011-07-25T22:23:04.000Z</LastModified>
<ETag>"0032a28286680abee71aed5d059c6a09"</ETag>
<Size>1785</Size>
<StorageClass>STANDARD</StorageClass>
</Contents>
</ListBucketResult>
そして次のループ:
while read_dom; do
echo "$ENTITY => $CONTENT"
done < input.xml
あなたは得るべきです:
=>
ListBucketResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/" =>
Name => sth-items
/Name =>
IsTruncated => false
/IsTruncated =>
Contents =>
Key => item-apple-iso@2x.png
/Key =>
LastModified => 2011-07-25T22:23:04.000Z
/LastModified =>
ETag => "0032a28286680abee71aed5d059c6a09"
/ETag =>
Size => 1785
/Size =>
StorageClass => STANDARD
/StorageClass =>
/Contents =>
したがって、while
Yuzemのようなループを作成した場合:
while read_dom; do
if [[ $ENTITY = "Key" ]] ; then
echo $CONTENT
fi
done < input.xml
S3バケット内のすべてのファイルのリストを取得します。
編集
何らかの理由でlocal IFS=\>
うまくいかず、グローバルに設定する場合は、次のように関数の最後でリセットする必要があります。
read_dom () {
ORIGINAL_IFS=$IFS
IFS=\>
read -d \< ENTITY CONTENT
IFS=$ORIGINAL_IFS
}
そうしないと、スクリプトの後半で行を分割すると、混乱します。
編集2
属性の名前と値のペアを分割するには、次のread_dom()
ように拡張できます。
read_dom () {
local IFS=\>
read -d \< ENTITY CONTENT
local ret=$?
TAG_NAME=${ENTITY%% *}
ATTRIBUTES=${ENTITY#* }
return $ret
}
次に、次のように必要なデータを解析して取得する関数を記述します。
parse_dom () {
if [[ $TAG_NAME = "foo" ]] ; then
eval local $ATTRIBUTES
echo "foo size is: $size"
elif [[ $TAG_NAME = "bar" ]] ; then
eval local $ATTRIBUTES
echo "bar type is: $type"
fi
}
その後、あなたがread_dom
呼び出す間parse_dom
:
while read_dom; do
parse_dom
done
次に、次のマークアップの例を示します。
<example>
<bar size="bar_size" type="metal">bars content</bar>
<foo size="1789" type="unknown">foos content</foo>
</example>
次の出力が表示されます。
$ cat example.xml | ./bash_xml.sh
bar type is: metal
foo size is: 1789
EDIT 3別のユーザーは、FreeBSDで問題が発生していると述べ、次のように、読み取りからの終了ステータスを保存し、read_domの最後にそれを返すことを提案しました。
read_dom () {
local IFS=\>
read -d \< ENTITY CONTENT
local RET=$?
TAG_NAME=${ENTITY%% *}
ATTRIBUTES=${ENTITY#* }
return $RET
}
それがうまくいかない理由は見当たらない
IFS=\< read ...
、これはIFSを読み取り呼び出しに対してのみ設定します。(私がread
xmlを解析するためにを使用する慣行を決して支持していないことに注意してください。そうすることは危険を伴うため、避けられるべきであると信じています。)
bashのみを使用すると、非常に簡単にそれを行うことができます。この関数を追加するだけです。
rdom () { local IFS=\> ; read -d \< E C ;}
これで、rdomをreadのように使用できますが、htmlドキュメントに使用できます。呼び出されると、rdomは要素を変数Eに、内容を変数Cに割り当てます。
たとえば、やりたいことを行うには:
while rdom; do
if [[ $E = title ]]; then
echo $C
exit
fi
done < xhtmlfile.xhtml > titleOfXHTMLPage.txt
シェルスクリプトから呼び出すことができるコマンドラインツールは次のとおりです。
また、コマンドラインまたはシェルスクリプトでXML処理を行うために、xmllintとxsltprocを小さなXSL変換スクリプトで使用しています。
xpathユーティリティを使用できます。これは、Perl XML-XPathパッケージとともにインストールされます。
使用法:
/usr/bin/xpath [filename] query
またはXMLStarlet。opensuseにインストールするには、次のコマンドを使用します。
sudo zypper install xmlstarlet
またはcnf xml
他のプラットフォームで試してください。
xpath
プリインストールされているはスクリプトのコンポーネントとしての使用には適していません。詳細については、たとえば、stackoverflow.com / questions / 15461737 /…を参照してください。
apt-get install xmlstarlet
これで十分です...
xpath xhtmlfile.xhtml '/html/head/title/text()' > titleOfXHTMLPage.txt
apt-get install libxml-xpath-perl
。
http://www.ofb.net/~egnor/xml2/からXML2をチェックしてください。XMLを行指向のフォーマットに変換する。
チャドの答えから始めて、コメントを適切に処理して、UMLを解析するための2つの小さな関数(2つ以上のbuですべてを混在させることができます)を備えたCOMPLETE作業ソリューションを次に示します。chadのものはまったく機能しなかったとは言えませんが、フォーマットが正しくないXMLファイルに関しては多くの問題がありました:コメントとスペース/ CR / TAB /などの誤配置を処理するには、もう少しトリッキーでなければなりません。
この回答の目的は、perl、pythonなどを使用した複雑なツールを使用せずに、UMLを解析する必要があるすべての人に、すぐに使用できるbash関数を提供することです。私に関しては、cpanをインストールできず、作業中の古い本番OSのperlモジュールもインストールできず、pythonを使用できません。
まず、この投稿で使用されているUML単語の定義:
<!-- comment... -->
<tag attribute="value">content...</tag>
編集:以下のハンドルで更新された関数:
xml_read_dom() {
# /programming/893585/how-to-parse-xml-in-bash
local ENTITY IFS=\>
if $ITSACOMMENT; then
read -d \< COMMENTS
COMMENTS="$(rtrim "${COMMENTS}")"
return 0
else
read -d \< ENTITY CONTENT
CR=$?
[ "x${ENTITY:0:1}x" == "x/x" ] && return 0
TAG_NAME=${ENTITY%%[[:space:]]*}
[ "x${TAG_NAME}x" == "x?xmlx" ] && TAG_NAME=xml
TAG_NAME=${TAG_NAME%%:*}
ATTRIBUTES=${ENTITY#*[[:space:]]}
ATTRIBUTES="${ATTRIBUTES//xmi:/}"
ATTRIBUTES="${ATTRIBUTES//xmlns:/}"
fi
# when comments sticks to !-- :
[ "x${TAG_NAME:0:3}x" == "x!--x" ] && COMMENTS="${TAG_NAME:3} ${ATTRIBUTES}" && ITSACOMMENT=true && return 0
# http://tldp.org/LDP/abs/html/string-manipulation.html
# INFO: oh wait it doesn't work on IBM AIX bash 3.2.16(1):
# [ "x${ATTRIBUTES:(-1):1}x" == "x/x" -o "x${ATTRIBUTES:(-1):1}x" == "x?x" ] && ATTRIBUTES="${ATTRIBUTES:0:(-1)}"
[ "x${ATTRIBUTES:${#ATTRIBUTES} -1:1}x" == "x/x" -o "x${ATTRIBUTES:${#ATTRIBUTES} -1:1}x" == "x?x" ] && ATTRIBUTES="${ATTRIBUTES:0:${#ATTRIBUTES} -1}"
return $CR
}
そして2番目のもの:
xml_read() {
# /programming/893585/how-to-parse-xml-in-bash
ITSACOMMENT=false
local MULTIPLE_ATTR LIGHT FORCE_PRINT XAPPLY XCOMMAND XATTRIBUTE GETCONTENT fileXml tag attributes attribute tag2print TAGPRINTED attribute2print XAPPLIED_COLOR PROSTPROCESS USAGE
local TMP LOG LOGG
LIGHT=false
FORCE_PRINT=false
XAPPLY=false
MULTIPLE_ATTR=false
XAPPLIED_COLOR=g
TAGPRINTED=false
GETCONTENT=false
PROSTPROCESS=cat
Debug=${Debug:-false}
TMP=/tmp/xml_read.$RANDOM
USAGE="${C}${FUNCNAME}${c} [-cdlp] [-x command <-a attribute>] <file.xml> [tag | \"any\"] [attributes .. | \"content\"]
${nn[2]} -c = NOCOLOR${END}
${nn[2]} -d = Debug${END}
${nn[2]} -l = LIGHT (no \"attribute=\" printed)${END}
${nn[2]} -p = FORCE PRINT (when no attributes given)${END}
${nn[2]} -x = apply a command on an attribute and print the result instead of the former value, in green color${END}
${nn[1]} (no attribute given will load their values into your shell; use '-p' to print them as well)${END}"
! (($#)) && echo2 "$USAGE" && return 99
(( $# < 2 )) && ERROR nbaram 2 0 && return 99
# getopts:
while getopts :cdlpx:a: _OPT 2>/dev/null
do
{
case ${_OPT} in
c) PROSTPROCESS="${DECOLORIZE}" ;;
d) local Debug=true ;;
l) LIGHT=true; XAPPLIED_COLOR=END ;;
p) FORCE_PRINT=true ;;
x) XAPPLY=true; XCOMMAND="${OPTARG}" ;;
a) XATTRIBUTE="${OPTARG}" ;;
*) _NOARGS="${_NOARGS}${_NOARGS+, }-${OPTARG}" ;;
esac
}
done
shift $((OPTIND - 1))
unset _OPT OPTARG OPTIND
[ "X${_NOARGS}" != "X" ] && ERROR param "${_NOARGS}" 0
fileXml=$1
tag=$2
(( $# > 2 )) && shift 2 && attributes=$*
(( $# > 1 )) && MULTIPLE_ATTR=true
[ -d "${fileXml}" -o ! -s "${fileXml}" ] && ERROR empty "${fileXml}" 0 && return 1
$XAPPLY && $MULTIPLE_ATTR && [ -z "${XATTRIBUTE}" ] && ERROR param "-x command " 0 && return 2
# nb attributes == 1 because $MULTIPLE_ATTR is false
[ "${attributes}" == "content" ] && GETCONTENT=true
while xml_read_dom; do
# (( CR != 0 )) && break
(( PIPESTATUS[1] != 0 )) && break
if $ITSACOMMENT; then
# oh wait it doesn't work on IBM AIX bash 3.2.16(1):
# if [ "x${COMMENTS:(-2):2}x" == "x--x" ]; then COMMENTS="${COMMENTS:0:(-2)}" && ITSACOMMENT=false
# elif [ "x${COMMENTS:(-3):3}x" == "x-->x" ]; then COMMENTS="${COMMENTS:0:(-3)}" && ITSACOMMENT=false
if [ "x${COMMENTS:${#COMMENTS} - 2:2}x" == "x--x" ]; then COMMENTS="${COMMENTS:0:${#COMMENTS} - 2}" && ITSACOMMENT=false
elif [ "x${COMMENTS:${#COMMENTS} - 3:3}x" == "x-->x" ]; then COMMENTS="${COMMENTS:0:${#COMMENTS} - 3}" && ITSACOMMENT=false
fi
$Debug && echo2 "${N}${COMMENTS}${END}"
elif test "${TAG_NAME}"; then
if [ "x${TAG_NAME}x" == "x${tag}x" -o "x${tag}x" == "xanyx" ]; then
if $GETCONTENT; then
CONTENT="$(trim "${CONTENT}")"
test ${CONTENT} && echo "${CONTENT}"
else
# eval local $ATTRIBUTES => eval test "\"\$${attribute}\"" will be true for matching attributes
eval local $ATTRIBUTES
$Debug && (echo2 "${m}${TAG_NAME}: ${M}$ATTRIBUTES${END}"; test ${CONTENT} && echo2 "${m}CONTENT=${M}$CONTENT${END}")
if test "${attributes}"; then
if $MULTIPLE_ATTR; then
# we don't print "tag: attr=x ..." for a tag passed as argument: it's usefull only for "any" tags so then we print the matching tags found
! $LIGHT && [ "x${tag}x" == "xanyx" ] && tag2print="${g6}${TAG_NAME}: "
for attribute in ${attributes}; do
! $LIGHT && attribute2print="${g10}${attribute}${g6}=${g14}"
if eval test "\"\$${attribute}\""; then
test "${tag2print}" && ${print} "${tag2print}"
TAGPRINTED=true; unset tag2print
if [ "$XAPPLY" == "true" -a "${attribute}" == "${XATTRIBUTE}" ]; then
eval ${print} "%s%s\ " "\${attribute2print}" "\${${XAPPLIED_COLOR}}\"\$(\$XCOMMAND \$${attribute})\"\${END}" && eval unset ${attribute}
else
eval ${print} "%s%s\ " "\${attribute2print}" "\"\$${attribute}\"" && eval unset ${attribute}
fi
fi
done
# this trick prints a CR only if attributes have been printed durint the loop:
$TAGPRINTED && ${print} "\n" && TAGPRINTED=false
else
if eval test "\"\$${attributes}\""; then
if $XAPPLY; then
eval echo "\${g}\$(\$XCOMMAND \$${attributes})" && eval unset ${attributes}
else
eval echo "\$${attributes}" && eval unset ${attributes}
fi
fi
fi
else
echo eval $ATTRIBUTES >>$TMP
fi
fi
fi
fi
unset CR TAG_NAME ATTRIBUTES CONTENT COMMENTS
done < "${fileXml}" | ${PROSTPROCESS}
# http://mywiki.wooledge.org/BashFAQ/024
# INFO: I set variables in a "while loop" that's in a pipeline. Why do they disappear? workaround:
if [ -s "$TMP" ]; then
$FORCE_PRINT && ! $LIGHT && cat $TMP
# $FORCE_PRINT && $LIGHT && perl -pe 's/[[:space:]].*?=/ /g' $TMP
$FORCE_PRINT && $LIGHT && sed -r 's/[^\"]*([\"][^\"]*[\"][,]?)[^\"]*/\1 /g' $TMP
. $TMP
rm -f $TMP
fi
unset ITSACOMMENT
}
そして最後に、rtrim、trim、echo2(stderrへ)関数:
rtrim() {
local var=$@
var="${var%"${var##*[![:space:]]}"}" # remove trailing whitespace characters
echo -n "$var"
}
trim() {
local var=$@
var="${var#"${var%%[![:space:]]*}"}" # remove leading whitespace characters
var="${var%"${var##*[![:space:]]}"}" # remove trailing whitespace characters
echo -n "$var"
}
echo2() { echo -e "$@" 1>&2; }
ああ、あなたは最初にいくつかのきちんとした色付け動的変数を定義してエクスポートする必要もあります:
set -a
TERM=xterm-256color
case ${UNAME} in
AIX|SunOS)
M=$(${print} '\033[1;35m')
m=$(${print} '\033[0;35m')
END=$(${print} '\033[0m')
;;
*)
m=$(tput setaf 5)
M=$(tput setaf 13)
# END=$(tput sgr0) # issue on Linux: it can produces ^[(B instead of ^[[0m, more likely when using screenrc
END=$(${print} '\033[0m')
;;
esac
# 24 shades of grey:
for i in $(seq 0 23); do eval g$i="$(${print} \"\\033\[38\;5\;$((232 + i))m\")" ; done
# another way of having an array of 5 shades of grey:
declare -a colorNums=(238 240 243 248 254)
for num in 0 1 2 3 4; do nn[$num]=$(${print} "\033[38;5;${colorNums[$num]}m"); NN[$num]=$(${print} "\033[48;5;${colorNums[$num]}m"); done
# piped decolorization:
DECOLORIZE='eval sed "s,${END}\[[0-9;]*[m|K],,g"'
関数を作成し、FPATH(ksh)またはFPATHのエミュレーション(bash)を介してそれらをロードする方法を知っている
そうでない場合は、すべてをコマンドラインにコピーして貼り付けます。
xml_read [-cdlp] [-x command <-a attribute>] <file.xml> [tag | "any"] [attributes .. | "content"]
-c = NOCOLOR
-d = Debug
-l = LIGHT (no \"attribute=\" printed)
-p = FORCE PRINT (when no attributes given)
-x = apply a command on an attribute and print the result instead of the former value, in green color
(no attribute given will load their values into your shell as $ATTRIBUTE=value; use '-p' to print them as well)
xml_read server.xml title content # print content between <title></title>
xml_read server.xml Connector port # print all port values from Connector tags
xml_read server.xml any port # print all port values from any tags
デバッグモード(-d)では、コメントと解析された属性がstderrに出力されます
./read_xml.sh: line 22: (-1): substring expression < 0
。
[ "x${ATTRIBUTES:(-1):1}x" == "x?x" ] ...
別のコマンドラインツールは私の新しいXidelですです。また、前述のxpath / xmlstarletとは異なり、XPath 2およびXQueryもサポートしています。
タイトルは次のように読むことができます:
xidel xhtmlfile.xhtml -e /html/head/title > titleOfXHTMLPage.txt
また、複数の変数をbashにエクスポートする優れた機能もあります。例えば
eval $(xidel xhtmlfile.xhtml -e 'title := //title, imgcount := count(//img)' --output-format bash )
$title
タイトルと$imgcount
ファイル内の画像の数を設定します。これは、bashで直接解析するのと同じくらい柔軟でなければなりません。
LinuxとWindowsのフォーマット間でXMLファイルのファイルパスを変換するための調査を行った結果、興味深いチュートリアルと解決策が見つかりました。
必要な機能を実行できる既製のコンソールユーティリティはかなりありますが、Pythonなどの汎用プログラミング言語で数行のコードを書くと、簡単に拡張して適応できるので、時間がかかりません。あなたの要望。
以下は、lxml
解析に使用するpythonスクリプトです。ファイルの名前またはURLを最初のパラメーターとして、XPath式を2番目のパラメーターとして受け取り、指定された式に一致する文字列/ノードを出力します。
#!/usr/bin/env python
import sys
from lxml import etree
tree = etree.parse(sys.argv[1])
xpath_expression = sys.argv[2]
# a hack allowing to access the
# default namespace (if defined) via the 'p:' prefix
# E.g. given a default namespaces such as 'xmlns="http://maven.apache.org/POM/4.0.0"'
# an XPath of '//p:module' will return all the 'module' nodes
ns = tree.getroot().nsmap
if ns.keys() and None in ns:
ns['p'] = ns.pop(None)
# end of hack
for e in tree.xpath(xpath_expression, namespaces=ns):
if isinstance(e, str):
print(e)
else:
print(e.text and e.text.strip() or etree.tostring(e, pretty_print=True))
lxml
でインストールできますpip install lxml
。ubuntuではを使用できますsudo apt install python-lxml
。
python xpath.py myfile.xml "//mynode"
lxml
また、入力としてURLを受け入れます。
python xpath.py http://www.feedforall.com/sample.xml "//link"
注:XMLに接頭辞のないデフォルトの名前空間(例:)がある場合、式
xmlns=http://abc...
からp
接頭辞(「hack」によって提供される)を使用する必要が//p:module
ありpom.xml
ます。たとえば、ファイルからモジュールを取得する場合などです。p
プレフィックスが既にXMLにマッピングされている場合は、別のプレフィックスを使用するようにスクリプトを変更する必要があります。
Apache Mavenファイルからモジュール名を抽出するという狭い目的に役立つ1回限りのスクリプト。ノード名(module
)の前にデフォルトの名前空間が付いていることに注意してください{http://maven.apache.org/POM/4.0.0}
。
pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modules>
<module>cherries</module>
<module>bananas</module>
<module>pears</module>
</modules>
</project>
module_extractor.py:
from lxml import etree
for _, e in etree.iterparse(open("pom.xml"), tag="{http://maven.apache.org/POM/4.0.0}module"):
print(e.text)
pip install
オーバーapt-get
またはyum
コールを。ありがとう!
これは、XML属性が必要な場合に機能します。
$ cat alfa.xml
<video server="asdf.com" stream="H264_400.mp4" cdn="limelight"/>
$ sed 's.[^ ]*..;s./>..' alfa.xml > alfa.sh
$ . ./alfa.sh
$ echo "$stream"
H264_400.mp4
「XML、JSONを解析しないでください...適切なツールなしでbashから」というのは健全なアドバイスですが、私はそうは思いません。これが副業である場合、適切なツールを探してそれを学ぶのはお腹いっぱいです。Awkは数分でそれを行うことができます。私のプログラムは上記のすべての種類のデータを処理する必要があります。地獄、私は30のツールをテストして、問題を数分で理解できれば、必要な5-7-10の異なる形式を解析したくありません。XMLやJSONなどは気にしません!それらすべてに対して単一のソリューションが必要です。
例として、私のSmartHomeプログラムは家を実行します。それをしている間、それは私が制御できない非常に多くの異なるフォーマットで大量のデータを読みます。必要なデータの読み取りに数分以上費やしたくないので、専用の適切なツールを使用することはありません。FSとRSの調整により、このawkソリューションはあらゆるテキスト形式で完全に機能します。しかし、主なタスクが主にその形式のデータのロードで作業することである場合、それは適切な答えではない場合があります!
昨日直面したbashからXMLを解析する問題。階層データ形式でこれを行う方法を次に示します。おまけとして、bashスクリプトの変数にデータを直接割り当てます。
シンを読みやすくするために、解決策を段階的に示します。OPテストデータから、test.xmlファイルを作成しました
XMLをbashで解析し、データを90文字で抽出します。
awk 'BEGIN { FS="<|>"; RS="\n" }; /host|username|password|dbname/ { print $2, $4 }' test.xml
私は通常、より読みやすいバージョンを使用します。なぜなら、私はしばしば別の方法でテストする必要があるので、実際に変更する方が簡単だからです。
awk 'BEGIN { FS="<|>"; RS="\n" }; { if ($0 ~ /host|username|password|dbname/) print $2,$4}' test.xml
形式がどのように呼ばれるかは気にしません。私は最も単純な解決策だけを求めます。この特定のケースでは、改行がレコード区切り(RS)および<>区切りフィールド(FS)であることがデータからわかります。私の元のケースでは、2つのレコード内の6つの値の複雑なインデックス付けを行い、それらを関連付けて、データが存在する場合とフィールド(レコード)が存在する場合と存在しない場合を見つけました。問題を完全に解決するには、4行のawkが必要でした。だから、それを使用する前にそれぞれのニーズにアイデアを適応させてください!
2番目の部分は、必要な文字列が行にある(RS)かどうかを単純に調べ、必要なフィールド(FS)を出力します。上記は、私がこの方法で使用した最後のコマンド(4倍以上)からコピーして適応するのに約30秒かかりました。これで完了です。90文字で行われます。
ただし、スクリプトの変数にデータを常にきれいに入れる必要があります。最初に次のように構成をテストします。
awk 'BEGIN { FS="<|>"; RS="\n" }; { if ($0 ~ /host|username|password|dbname/) print $2"=\""$4"\"" }' test.xml
場合によっては、printの代わりにprintfを使用します。すべてが問題ないように見えたら、変数への値の割り当てを終了します。私は多くの人が「評価」は「悪」だと思っていることを知っています。コメントする必要はありません:) Trickは何年もの間、私の4つのネットワークすべてで完全に機能します。しかし、これが悪い習慣である理由がわからない場合は、学習を続けてください。bash変数の割り当てと十分な間隔を含む私のソリューションでは、すべてを実行するために120文字が必要です。
eval $( awk 'BEGIN { FS="<|>"; RS="\n" }; { if ($0 ~ /host|username|password|dbname/) print $2"=\""$4"\"" }' test.xml ); echo "host: $host, username: $username, password: $password dbname: $dbname"