我有两个文件:file1和file2。以下是文件内容的示例:
<TG>
<entry name="KEYNAME" val="" type="string" />
<entry name="KEYTYPE" val="" type="string" />
<entry name="TIMEZONE_OFFSET" val="-240" type="INT16" />
...
</TG>
我想检查file2中是否存在file1中的某些行(包含字符串&#34;条目名称&#34;的行),如果是,则比较两行是否相同。
我通过复制file1来创建file2,然后我更改了一些值。问题是比较两个字符串变量不会返回正确的值。虽然在显示两个变量时我可以看到它们是相同的,但比较的结果却表明它们不相同。我正在使用Ksh。这是我的代码:
while read p; do
if [[ $p == *"entry name"* ]]; then
PARAM_NAME=$(echo $p | cut -d '"' -f2)
echo $PARAM_NAME
PARAM_OLD=$(grep $PARAM_NAME file2)
if [[ $PARAM_OLD == *"entry name"* ]]; then
echo $PARAM_OLD
echo $p
if [ "$PARAM_OLD" = "$p" ]; then
echo 'Identical values'
else
echo 'Different values'
fi
else
echo "$PARAM_NAME does not exist in previous version file. Using default value"
fi
fi
done <file1
我尝试了所有可能的括号,等号和引号([],[[]],=,==,&#34;&#34;,&#39;&#34;&#34; &#39;等。)
以下是我得到的输出:
<entry name="KEYNAME" val="" type="string" />
KEYNAME
<entry name="KEYNAME" val="" type="string" />
<entry name="KEYNAME" val="" type="string" />
Different values
<entry name="KEYTYPE" val="" type="string" />
KEYTYPE
<entry name="KEYTYPE" val="" type="string" />
<entry name="KEYTYPE" val="" type="string" />
Different values
<entry name="TIMEZONE_OFFSET" val="-24" type="INT16" />
TIMEZONE_OFFSET
<entry name="TIMEZONE_OFFSET" val="-240" type="INT16" />
<entry name="TIMEZONE_OFFSET" val="-24" type="INT16" />
Different values
我仍然觉得字符串不同!我将不胜感激任何解释和帮助。
答案 0 :(得分:0)
在if语句中只有1 =,将其更改为2:
if [ "$PARAM_OLD" = "$p" ]; then
为:
if [ "$PARAM_OLD" == "$p" ]; then
另外(现在不是问题,但可能是你的下一个问题),环绕$ PARAM_OLD“在以下行中:
if [[ $PARAM_OLD == *"entry name"* ]]; then
所以它变成了:
if [[ "$PARAM_OLD" == *"entry name"* ]]; then
答案 1 :(得分:0)
最近/较新的操作系统都支持ksh和ksh93。
使用ksh93,我们可以使用关联数组将自己限制为单个遍历每个文件。
首先是一些样本数据:
$ cat file1
<TG>
<entry name="KEYNAME" val="" type="string" />
<entry name="KEYTYPE" val="" type="string" />
<entry name="KEYATTRIB" val="" type="string" />
<entry name="TIMEZONE_OFFSET" val="-241" type="INT16" />
</TG>
$ cat file2
<TG>
<entry name="KEYNAME" val="" type="string" />
<entry name="KEYTYPE" val="" type="stringX" />
<entry name="TIMEZONE_OFFSET" val="-240" type="INT16" />
</TG>
ksh93脚本:
$ cat my_comp
#!/bin/ksh93
unset pline
typeset -A pline
# pull unique list of 'entry name' lines from file2 and store in our associative array pline[]:
egrep "entry name" file2 | sort -u | while read line
do
# strip out the 'entry name' value
x=${line#*\"}
pname=${x%%\"*}
# use the 'entry name' value as the index for our pline[] array
pline[${pname}]=${line}
done
# for each unique 'entry name' line in file1, see if we have a match in file2 (aka our pline[] array):
egrep "entry name" file1 | sort -u | while read line
do
# again, strip out the 'entry name' value
x=${line#*\"}
pname=${x%%\"*}
# if pname does not exist in file2
[ "${pline[${pname}]}" = '' ] && \
echo "\npname = '${pname}' : Does not exist in file2. Using default value:" && \
echo "file1: ${line}" && \
continue
# if pname exists in file2 but line is different
[ "${pline[${pname}]}" = "${line}" ] && \
echo "\npname = '${pname}' : Identical values for pname" && \
echo "file1: ${line}" && \
echo "file2: ${pline[${pname}]}" && \
continue
# if pname exists in file2 and line is the same
[ "${pline[${pname}]}" != "${line}" ] && \
echo "\npname = '${pname}' : Different values for pname" && \
echo "file1: ${line}" && \
echo "file2: ${pline[${pname}]}"
done
针对示例文件运行脚本:
$ my_comp
pname = 'KEYATTRIB' : Does not exist in file2. Using default value:
file1: <entry name="KEYATTRIB" val="" type="string" />
pname = 'KEYNAME' : Identical values for pname
file1: <entry name="KEYNAME" val="" type="string" />
file2: <entry name="KEYNAME" val="" type="string" />
pname = 'KEYTYPE' : Different values for pname
file1: <entry name="KEYTYPE" val="" type="string" />
file2: <entry name="KEYTYPE" val="" type="stringX" />
pname = 'TIMEZONE_OFFSET' : Different values for pname
file1: <entry name="TIMEZONE_OFFSET" val="-241" type="INT16" />
file2: <entry name="TIMEZONE_OFFSET" val="-240" type="INT16" />
回到简单的&#39;基本的ksh:
$ cat my_comp2
#!/bin/ksh
egrep "entry name" file1 | sort -u | while read line1
do
x=${line1#*\"}
pname=${x%%\"*}
# see if we can find a matching line in file2; need to strip off leading
# spaces in order to match with line1
unset line2
line2=$( egrep "entry name.*${pname}" file2 | sed 's/^ *//g' )
# if pname does not exist in file2
[ "${line2}" = '' ] && \
echo "\npname = '${pname}' : Does not exist in file2. Using default value:" && \
echo "file1: ${line1}" && \
continue
# if pname exists in file2 but lines are different
[ "${line2}" = "${line1}" ] && \
echo "\npname = '${pname}' : Identical values for pname" && \
echo "file1: ${line1}" && \
echo "file2: ${line2}" && \
continue
# if pname exists in file2 and lines are the same
[ "${line2}" != "${line1}" ] && \
echo "\npname = '${pname}' : Different values for pname" && \
echo "file1: ${line1}" && \
echo "file2: ${line2}"
done
针对示例文件运行脚本:
$ my_comp2
pname = 'KEYATTRIB' : Does not exist in file2. Using default value:
file1: <entry name="KEYATTRIB" val="" type="string" />
pname = 'KEYNAME' : Identical values for pname
file1: <entry name="KEYNAME" val="" type="string" />
file2: <entry name="KEYNAME" val="" type="string" />
pname = 'KEYTYPE' : Different values for pname
file1: <entry name="KEYTYPE" val="" type="string" />
file2: <entry name="KEYTYPE" val="" type="stringX" />
pname = 'TIMEZONE_OFFSET' : Different values for pname
file1: <entry name="TIMEZONE_OFFSET" val="-241" type="INT16" />
file2: <entry name="TIMEZONE_OFFSET" val="-240" type="INT16" />
答案 2 :(得分:0)
以下内容将您的内容转换为以制表符分隔的键值形式:
xml_to_tsv() {
xmlstarlet sel -t -m '//entry[@name]' -v ./@name -o $'\t' -v ./@value -n
}
因此,如果要比较两个流,以下内容将仅发出第一个文件唯一的行:
comm -23 <(xml_to_tsv <one.xml | sort) <(xml_to_tsv <two.xml | sort)
...以下内容仅发出第二行唯一的行:
comm -13 <(xml_to_tsv <one.xml | sort) <(xml_to_tsv <two.xml | sort)
如果您没有安装XMLStarlet,则可以生成XSLT模板以执行相同的操作。因此,如果您有以下文件extract_entries.xslt
:
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:exslt="http://exslt.org/common" version="1.0" extension-element-prefixes="exslt">
<xsl:output omit-xml-declaration="yes" indent="no"/>
<xsl:template match="/">
<xsl:for-each select="//entry[@name]">
<xsl:call-template name="value-of-template">
<xsl:with-param name="select" select="./@name"/>
</xsl:call-template>
<xsl:text> </xsl:text>
<xsl:call-template name="value-of-template">
<xsl:with-param name="select" select="./@value"/>
</xsl:call-template>
<xsl:value-of select="' '"/>
</xsl:for-each>
</xsl:template>
<xsl:template name="value-of-template">
<xsl:param name="select"/>
<xsl:value-of select="$select"/>
<xsl:for-each select="exslt:node-set($select)[position()>1]">
<xsl:value-of select="' '"/>
<xsl:value-of select="."/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
...您可以在根本没有XMLStarlet的系统上使用以下xml_to_tsv
实现:
xml_to_tsv() {
xsltproc extract_entries.xslt -
}
答案 3 :(得分:0)
使用以下两个数据文件和一个转换文件:
file1.xml:
<TG>
<entry name="common" value="foo"/>
<entry name="changed" value="bar"/>
<entry name="unique1" val="qux"/>
</TG>
file2.xml:
<TG>
<entry name="common" value="foo"/>
<entry name="changed" value="bar"/>
<entry name="unique2" val="quux"/>
</TG>
transform.xslt:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<!-- To be passed with xsltproc's stringparam argument -->
<xsl:param name="other"/>
<!-- Convenience aliases -->
<xsl:variable name="file1" select="/"/>
<xsl:variable name="file2" select="document($other)"/>
<xsl:template match="/">
<results>
<common_entries>
<xsl:for-each select="$file1/TG/entry[@name]">
<xsl:variable name="node1" select="."/>
<xsl:variable name="node2" select="$file2/TG/entry[@name=$node1/@name]"/>
<!-- xpath 1.0, the only version people use, lacks the deep-equal() function -->
<xsl:if test="$node1/@value = $node2/@value">
<xsl:apply-templates select="$node1"/>
</xsl:if>
</xsl:for-each>
</common_entries>
<changed_entries>
<xsl:for-each select="$file1/TG/entry[@name]">
<xsl:variable name="node1" select="."/>
<xsl:variable name="node2" select="$file2/TG/entry[@name=$node1/@name]"/>
<xsl:if test="$node1/@value != $node2/@value">
<diff>
<old>
<xsl:apply-templates select="$node1"/>
</old>
<new>
<xsl:apply-templates select="$node2"/>
</new>
</diff>
</xsl:if>
</xsl:for-each>
</changed_entries>
<unique1_entries>
<xsl:for-each select="$file1/TG/entry[not(@name=$file2/TG/entry/@name)]">
<xsl:apply-templates select="."/>
</xsl:for-each>
</unique1_entries>
<unique2_entries>
<xsl:for-each select="$file2/TG/entry[not(@name=$file1/TG/entry/@name)]">
<xsl:apply-templates select="."/>
</xsl:for-each>
</unique2_entries>
</results>
</xsl:template>
<!-- Standard identity transform -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
然后运行xsltproc --stringparam other file2.xml transform.xslt file1.xml
将产生:
<?xml version="1.0"?>
<results>
<common_entries>
<entry name="common" value="foo"/>
</common_entries>
<changed_entries>
<diff>
<old>
<entry name="changed" value="bar"/>
</old>
<new>
<entry name="changed" value="baz"/>
</new>
</diff>
</changed_entries>
<unique1_entries>
<entry name="unique1" val="qux"/>
</unique1_entries>
<unique2_entries>
<entry name="unique2" val="quux"/>
</unique2_entries>
</results>