试图弄清楚如何将函数转换为接受管道标准输入
Trying to figure out how to convert function to accept piped stdin
我正在研究一种使用 bash 轻松解析 XML 的方法,用于特定目的。我已经将它与我在该站点上找到的一些代码一起使用,然后我重新编码了所有内容,因为该代码运行良好。这目前正在使用一个函数,我必须将数据放在一个文件中才能处理它。这是它的工作状态:
[ ~]$ cat testxml.xml
CTYPE PARTS SYSTEM "parts.dtd">
<?xml-stylesheet type="text/css" href="xmlpartsstyle.css"?>
<PARTS>
<TITLE>Computer Parts</TITLE>
<PART>
<ITEM>Motherboard</ITEM>
<MANUFACTURER>ASUS</MANUFACTURER>
<MODEL>P3B-F</MODEL>
<COST> 123.00</COST>
</PART>
<PART>
<ITEM>Video Card</ITEM>
<MANUFACTURER>ATI</MANUFACTURER>
<MODEL>All-in-Wonder Pro</MODEL>
<COST> 160.00</COST>
</PART>
<PART>
<ITEM>Sound Card</ITEM>
<MANUFACTURER>Creative Labs</MANUFACTURER>
<MODEL>Sound Blaster Live</MODEL>
<COST> 80.00</COST>
</PART>
<PART>
<ITEM> 20 inch Monitor</ITEM>
<MANUFACTURER>LG Electronics</MANUFACTURER>
<MODEL> 995E</MODEL>
<COST> 290.00</COST>
</PART>
</PARTS>
[ ~]$
[ ~]$ rdom () { local IFS=\> ; read -d \< E C ;} ; while rdom; do if [[ $E = 'PART' ]] || [[ $E = 'ITEM' ]] || [[ $E = 'COST' ]] ; then echo $E: $C ; fi ; done < testxml.xml | xargs -L3
PART: ITEM: Motherboard COST: 123.00
PART: ITEM: Video Card COST: 160.00
PART: ITEM: Sound Card COST: 80.00
PART: ITEM: 20 inch Monitor COST: 290.00
[ ~]$
如您所见,这提取了我正在寻找的数据,并且我能够重新格式化它以满足我的需要。但是,我更愿意让它接受来自 stdin 的输入,例如:
cat out.xml2 | IFS=\> ; until [ EOF ]; do read -d \< E C ; if [[ $E = 'PART' ]] || [[ $E = 'ITEM' ]] || [[ $E = 'COST' ]] ; then echo $E: $C ; fi ; done;
此代码永远不会结束循环。这可能是不可能的,我只是不明白循环是如何结束的 b/c 它有 "rdom" 作为它等待显示循环终止的表达式。我已经用 while 循环等尝试过这个。不确定如何确定数据何时不再存在以便循环可以结束。我觉得可能有更好的方法来重组我完全错过的这个。我喜欢能够使用 stdin b/c 它可以轻松使用一个衬垫。我正在解析的实际数据要大得多,而且是多维的。我出于测试目的创建了这个示例。第一个示例适用于我拥有的大数据。最终结果是我试图让它从标准输入而不是从文件中解析。非常感谢任何建议。
杰夫
尝试:
$ rdom() { local IFS=\> ; while read -d \< E C ; do if [[ $E = 'PART' ]] || [[ $E = 'ITEM' ]] || [[ $E = 'COST' ]] ; then echo $E: $C ; fi ; done; }
$ rdom <out.xml2
PART:
ITEM: Motherboard
COST: 123.00
PART:
ITEM: Video Card
COST: 160.00
PART:
ITEM: Sound Card
COST: 80.00
PART:
ITEM: 20 inch Monitor
COST: 290.00
或者,不使用函数定义但仍从标准输入获取输入:
{ IFS=\> ; while read -d \< E C ; do if [[ $E = 'PART' ]] || [[ $E = 'ITEM' ]] || [[ $E = 'COST' ]] ; then echo $E: $C ; fi ; done; } <out.xml2
因为题目没有显示想要的输出,不知道是不是你想要的。
一些评论:
cat out.xml2 | IFS=\> ;
将out.xml2的文本发送给变量赋值IFS=\>
。变量赋值完成后,文本被丢弃。
until [ EOF ]; do read -d \< E C ; ...
没有按照您的意愿进行。在shell中,字符串EOF只有三个字符。相比之下,while read -d \< E C ; do ...
会在输入耗尽时停止。
管道示例
为了证明上述方法与管道一起工作,而不仅仅是从文件重定向,请尝试:
cat out.xml2 | rdom
或者:
cat out.xml2 | { IFS=\> ; while read -d \< E C ; do if [[ $E = 'PART' ]] || [[ $E = 'ITEM' ]] || [[ $E = 'COST' ]] ; then echo $E: $C ; fi ; done; }
替代输出格式
继续使用 cat
作为管道的替代品:
$ cat out.xml2 | { IFS=\> ; while read -d \< E C ; do case "$E" in PART) printf "%s:" "$E";; ITEM) printf " %s: %s" "$E" "$C";; COST) printf " %s: %s\n" "$E" "$C";; esac ; done; }
PART: ITEM: Motherboard COST: 123.00
PART: ITEM: Video Card COST: 160.00
PART: ITEM: Sound Card COST: 80.00
PART: ITEM: 20 inch Monitor COST: 290.00
我正在研究一种使用 bash 轻松解析 XML 的方法,用于特定目的。我已经将它与我在该站点上找到的一些代码一起使用,然后我重新编码了所有内容,因为该代码运行良好。这目前正在使用一个函数,我必须将数据放在一个文件中才能处理它。这是它的工作状态:
[ ~]$ cat testxml.xml
CTYPE PARTS SYSTEM "parts.dtd">
<?xml-stylesheet type="text/css" href="xmlpartsstyle.css"?>
<PARTS>
<TITLE>Computer Parts</TITLE>
<PART>
<ITEM>Motherboard</ITEM>
<MANUFACTURER>ASUS</MANUFACTURER>
<MODEL>P3B-F</MODEL>
<COST> 123.00</COST>
</PART>
<PART>
<ITEM>Video Card</ITEM>
<MANUFACTURER>ATI</MANUFACTURER>
<MODEL>All-in-Wonder Pro</MODEL>
<COST> 160.00</COST>
</PART>
<PART>
<ITEM>Sound Card</ITEM>
<MANUFACTURER>Creative Labs</MANUFACTURER>
<MODEL>Sound Blaster Live</MODEL>
<COST> 80.00</COST>
</PART>
<PART>
<ITEM> 20 inch Monitor</ITEM>
<MANUFACTURER>LG Electronics</MANUFACTURER>
<MODEL> 995E</MODEL>
<COST> 290.00</COST>
</PART>
</PARTS>
[ ~]$
[ ~]$ rdom () { local IFS=\> ; read -d \< E C ;} ; while rdom; do if [[ $E = 'PART' ]] || [[ $E = 'ITEM' ]] || [[ $E = 'COST' ]] ; then echo $E: $C ; fi ; done < testxml.xml | xargs -L3
PART: ITEM: Motherboard COST: 123.00
PART: ITEM: Video Card COST: 160.00
PART: ITEM: Sound Card COST: 80.00
PART: ITEM: 20 inch Monitor COST: 290.00
[ ~]$
如您所见,这提取了我正在寻找的数据,并且我能够重新格式化它以满足我的需要。但是,我更愿意让它接受来自 stdin 的输入,例如:
cat out.xml2 | IFS=\> ; until [ EOF ]; do read -d \< E C ; if [[ $E = 'PART' ]] || [[ $E = 'ITEM' ]] || [[ $E = 'COST' ]] ; then echo $E: $C ; fi ; done;
此代码永远不会结束循环。这可能是不可能的,我只是不明白循环是如何结束的 b/c 它有 "rdom" 作为它等待显示循环终止的表达式。我已经用 while 循环等尝试过这个。不确定如何确定数据何时不再存在以便循环可以结束。我觉得可能有更好的方法来重组我完全错过的这个。我喜欢能够使用 stdin b/c 它可以轻松使用一个衬垫。我正在解析的实际数据要大得多,而且是多维的。我出于测试目的创建了这个示例。第一个示例适用于我拥有的大数据。最终结果是我试图让它从标准输入而不是从文件中解析。非常感谢任何建议。
杰夫
尝试:
$ rdom() { local IFS=\> ; while read -d \< E C ; do if [[ $E = 'PART' ]] || [[ $E = 'ITEM' ]] || [[ $E = 'COST' ]] ; then echo $E: $C ; fi ; done; }
$ rdom <out.xml2
PART:
ITEM: Motherboard
COST: 123.00
PART:
ITEM: Video Card
COST: 160.00
PART:
ITEM: Sound Card
COST: 80.00
PART:
ITEM: 20 inch Monitor
COST: 290.00
或者,不使用函数定义但仍从标准输入获取输入:
{ IFS=\> ; while read -d \< E C ; do if [[ $E = 'PART' ]] || [[ $E = 'ITEM' ]] || [[ $E = 'COST' ]] ; then echo $E: $C ; fi ; done; } <out.xml2
因为题目没有显示想要的输出,不知道是不是你想要的。
一些评论:
cat out.xml2 | IFS=\> ;
将out.xml2的文本发送给变量赋值IFS=\>
。变量赋值完成后,文本被丢弃。until [ EOF ]; do read -d \< E C ; ...
没有按照您的意愿进行。在shell中,字符串EOF只有三个字符。相比之下,while read -d \< E C ; do ...
会在输入耗尽时停止。
管道示例
为了证明上述方法与管道一起工作,而不仅仅是从文件重定向,请尝试:
cat out.xml2 | rdom
或者:
cat out.xml2 | { IFS=\> ; while read -d \< E C ; do if [[ $E = 'PART' ]] || [[ $E = 'ITEM' ]] || [[ $E = 'COST' ]] ; then echo $E: $C ; fi ; done; }
替代输出格式
继续使用 cat
作为管道的替代品:
$ cat out.xml2 | { IFS=\> ; while read -d \< E C ; do case "$E" in PART) printf "%s:" "$E";; ITEM) printf " %s: %s" "$E" "$C";; COST) printf " %s: %s\n" "$E" "$C";; esac ; done; }
PART: ITEM: Motherboard COST: 123.00
PART: ITEM: Video Card COST: 160.00
PART: ITEM: Sound Card COST: 80.00
PART: ITEM: 20 inch Monitor COST: 290.00