比较linux KSH脚本中的两个字符串

时间:2017-08-15 13:46:12

标签: linux shell ksh string-comparison

我有两个文件: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

我仍然觉得字符串不同!我将不胜感激任何解释和帮助。

4 个答案:

答案 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转换为制表符分隔的键/值对

以下内容将您的内容转换为以制表符分隔的键值形式:

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

如果您没有安装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="'&#10;'"/>
    </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()&gt;1]">
      <xsl:value-of select="'&#10;'"/>
      <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>