한 파일에서 문자열을 추출하여 다른 파일에 삽입(수정)하는 방법은 무엇입니까?

한 파일에서 문자열을 추출하여 다른 파일에 삽입(수정)하는 방법은 무엇입니까?

질문은 다음과 같습니다.

데이터가 포함된 xml 파일이 있고 새 파일에 쓸 데이터의 작은 부분을 찾고 있습니다. 요청에 따라 콘텐츠가 단축되었습니다.

type=dhcp-client인 경우 코드 조각은 다음과 같습니다.

    <deviceconfig>
      <system>
        <type>
          <dhcp-client>
            <send-hostname>yes</send-hostname>
          </dhcp-client>
        </type>
        <hostname>Firewall</hostname>
      </system>
    </deviceconfig>

유형=정적이면 조각화

    <deviceconfig>
      <system>
        <type>
          <static/>
        </type>
        <hostname>Firewall</hostname>
        <permitted-ip>
          <entry name="192.168.0.0/24"/>
        </permitted-ip>
        <ip-address>192.168.0.2</ip-address>
        <netmask>255.255.255.0</netmask>
        <default-gateway>192.168.0.1</default-gateway>
      </system>
    <network>
      <interface>
        <ethernet>
          <entry name="ethernet1/1">
            <layer3>
              <ip>
                <entry name="192.168.0.5/24"/>
              </ip>
            </layer3>
          </entry>
        </ethernet>
      </interface>
      <virtual-router>
        <entry name="default">
          <routing-table>
            <ip>
              <static-route>
                <entry name="default-route">
                  <nexthop>
                    <ip-address>192.168.0.1</ip-address>
                  </nexthop>
                  <interface>ethernet1/4</interface>
                  <destination>0.0.0.0/0</destination>
                </entry>
              </static-route>
            </ip>
          </routing-table>
        </entry>
      </virtual-router>
    </network>

4개의 관련 값은 "시스템" 태그 내에서 고유하거나 존재하지 않습니다. <system></system> IP 주소와 같은 것들은 시스템 외부의 다른 곳에 다시 나타날 수 있지만 <system></system> 유형이 다음과 같은 경우에만 시스템 내부의 값을 확인합니다. 정적이 아니므로 나타나지 않습니다. DHCP 클라이언트로 설정하겠습니다.

유형이 dhcp인 경우 필요한 파일 결과는 다음과 같습니다.

type=dhcp-client

유형이 정적인 경우 파일에 필요한 결과는 다음과 같습니다.

type=static
ip-address=192.168.0.2
default-gateway=192.168.0.1
netmask=255.255.255.0

이 작업을 효율적으로 수행하고 기존 시스템에 통합하는 방법을 잘 모르겠습니다.PHP파일에 저장합니다(따라서 작업하려면 exec를 사용하거나 그냥 php를 사용하는 것이 좋습니다).

또한 우분투 서버 시스템에 기본적으로 설치되는 도구만 사용할 수 있고 다른 패키지는 사용할 수 없습니다.

추신: 이것은 실제로 전체/완전한 사용 사례이므로 이 두 가지 예 외에 다른 출력을 생성할 필요가 없습니다. 도움이나 조언을 보내주셔서 감사합니다 :)

답변1

XML 인식 도구에 액세스할 수 없고 입력 파일이 표시된 것처럼 간단하고 규칙적이라고 가정하면 게시한 입력 예제를 기반으로 예상되는 출력이 생성됩니다.

$ cat tst.awk
BEGIN { FS="[[:space:]]*[<>][[:space:]]*"; OFS="=" }
$2 == "system"  { inBlock=1 }
inBlock { f[$2] = $3 }
$2 == "/system" { inBlock=0 }
END {
    if ("ip-address" in f) {
        print "type", "static"
        print "ip-address", f["ip-address"]
        print "default-gateway", f["default-gateway"]
        print "netmask", f["netmask"]
    }
    else {
        print "type", "dhcp-client"
    }
}

.

$ awk -f tst.awk absentFile
type=dhcp-client

.

$ awk -f tst.awk presentFile
type=static
ip-address=192.168.0.2
default-gateway=192.168.0.1
netmask=255.255.255.0

위의 내용은 다음 입력 파일에서 실행되었습니다.

$ tail -n +1 absentFile presentFile
==> absentFile <==
    <deviceconfig>
      <system>
        <type>
          <dhcp-client>
            <send-hostname>yes</send-hostname>
          </dhcp-client>
        </type>
        <hostname>Firewall</hostname>
      </system>
    </deviceconfig>

==> presentFile <==
    <deviceconfig>
      <system>
        <type>
          <static/>
        </type>
        <hostname>Firewall</hostname>
        <permitted-ip>
          <entry name="192.168.0.0/24"/>
        </permitted-ip>
        <ip-address>192.168.0.2</ip-address>
        <netmask>255.255.255.0</netmask>
        <default-gateway>192.168.0.1</default-gateway>
      </system>
    <network>
      <interface>
        <ethernet>
          <entry name="ethernet1/1">
            <layer3>
              <ip>
                <entry name="192.168.0.5/24"/>
              </ip>
            </layer3>
          </entry>
        </ethernet>
      </interface>
      <virtual-router>
        <entry name="default">
          <routing-table>
            <ip>
              <static-route>
                <entry name="default-route">
                  <nexthop>
                    <ip-address>192.168.0.1</ip-address>
                  </nexthop>
                  <interface>ethernet1/4</interface>
                  <destination>0.0.0.0/0</destination>
                </entry>
              </static-route>
            </ip>
          </routing-table>
        </entry>
      </virtual-router>
    </network>

답변2

글쎄요, 제가 직접 답을 찾았습니다...

사실, PHP가 없는 것보다 PHP가 훨씬 더 간단합니다.

하지만 완성하는데 시간이 많이 걸렸네요^^

#load the file as simplexml object and then switch into system
#https://www.w3schools.com/php/func_simplexml_load_file.asp
$xml=simplexml_load_file('./myfile') or die("Error: Cannot create object");
$xml=$xml->system

#put the whole string(s) into a variable, getname gets the name of the object itself if it exists
#https://www.w3schools.com/php/func_simplexml_getname.asp
$output='type=' . $xml -> type -> static -> getName() . $xml -> type -> {'dhcp-client'} -> getName() . "\nip-address=" . $xml -> {'ip-address'} . "\ndefault-gateway=" . $xml -> {'default-gateway'} . "\nnetmask=" . $xml -> netmask;

#write the output into a file
#https://www.w3schools.com/php/func_filesystem_file_put_contents.asp
file_put_contents('./myoutputfile', $output );

그러면 첫 번째 스니펫에 대해 다음과 같은 출력이 제공됩니다(마지막 세 줄에 값이 제공되지 않아도 괜찮습니다. 그렇지 않으면 값이 먼저 존재하는지 확인할 수 있습니다).

type=dhcp-client
ip-address=
default-gateway=
netmask=

두 번째 스니펫의 출력:

type=static
ip-address=192.168.0.2
default-gateway=192.168.0.1
netmask=255.255.255.0

모두의 도움에 감사드립니다 :)

답변3

다음 스크립트를 사용할 수 있습니다 ip-parse.sh.

#!/bin/bash

#https://stackoverflow.com/questions/22221277/bash-grep-between-two-lines-with-specified-string
#https://www.cyberciti.biz/faq/bash-remove-whitespace-from-string/
#https://stackoverflow.com/questions/1251999/how-can-i-replace-a-newline-n-using-sed
sed -n '/\<system\>/,/system\>/p' ~/Desktop/x-test.xml | sed -e 's/^[ \t]*//' > ~/Desktop/x-system.xml
sed ':a;N;$!ba;s/\n/ /g' ~/Desktop/x-system.xml > /tmp/xml-one-line.xml

#[]test to see if the "system" section ...
#... has the word hostname occuring before the word ip-address    
#https://stackoverflow.com/questions/33265650/grep-for-a-string-in-a-specific-order
if [ -n "$(grep hostname.*ip-address /tmp/xml-one-line.xml)" ]; then 
    echo "File contains hostname and ip-address, in that order."
else
    echo "type=dhcp-client" ; echo "type=dhcp-client" > ~/Desktop/network-config.txt ; exit
fi

#http://www.compciv.org/topics/bash/variables-and-substitution/    
ipaddress="$(grep ip-address ~/Desktop/x-system.xml | sed 's/<ip-address>//g; s/<\/ip-address>//g')"  
defaultgateway="$(grep default-gateway ~/Desktop/x-system.xml | sed 's/<default-gateway>//g; s/<\/default-gateway>//g')"
netmask="$(grep netmask ~/Desktop/x-system.xml | sed 's/<netmask>//g; s/<\/netmask>//g')"

echo "type=static" > ~/Desktop/network-config.txt
echo "ip-address=$ipaddress" >> ~/Desktop/network-config.txt
echo "default-gateway=$defaultgateway" >> ~/Desktop/network-config.txt
echo "netmask=$netmask" >> ~/Desktop/network-config.txt

적용 예:

paul@mxg6:~/Desktop$ ./ip-parse.sh   
File contains hostname and ip-address, in that order.  
paul@mxg6:~/Desktop$ cat network-config.txt   
type=static  
ip-address=192.168.0.2  
default-gateway=192.168.0.1  
netmask=255.255.255.0   

호스트 이름이 IP 주소 앞에 오는지 확인할 필요가 없고 중간 파일 대신 변수를 사용하려는 경우 다음을 시도하십시오.

#!/bin/bash

xsystemxml="$(sed -n '/\<system\>/,/system\>/p' ~/Desktop/x-test.xml \
| sed -e 's/^[ \t]*//')"

if [ -n "$(echo $xsystemxml | grep ip-address)" ]; then 
    echo "System section contains ip-address."
else
    echo "type=dhcp-client"
    echo "type=dhcp-client" > ~/Desktop/network-config.txt
    exit
fi

ipaddress="$(echo "$xsystemxml" | grep "ip-address" \
| sed 's/<ip-address>//g; s/<\/ip-address>//g')"

defaultgateway="$(echo "$xsystemxml" | grep "default-gateway" \
| sed 's/<default-gateway>//g; s/<\/default-gateway>//g')"

netmask="$(echo "$xsystemxml" | grep "netmask" \
| sed 's/<netmask>//g; s/<\/netmask>//g')"

echo "type=static" > ~/Desktop/network-config.txt
echo "ip-address=$ipaddress" >> ~/Desktop/network-config.txt
echo "default-gateway=$defaultgateway" >> ~/Desktop/network-config.txt
echo "netmask=$netmask" >> ~/Desktop/network-config.txt

답변4

다음 답변은 here 에서 나옵니다.https://stackoverflow.com/questions/893585/how-to-parse-xml-in-bash, 간단한 스크립트를 작성했습니다

#!/bin/bash

read_dom () {
    local IFS=\>
    read -d \< ENTITY CONTENT
}

found=0
while read_dom; do
    if [[ $ENTITY = "ip-address" ]] && [[ $last_tag = "/hostname" ]] || [[ $ENTITY = "netmask" ]] || [[ $ENTITY = "default-gateway" ]]; then
        if [[ $found = 0 ]]; then
            echo "type=static"
        fi

        echo "$ENTITY=$CONTENT"
        found="1"
    fi
    last_tag=$ENTITY
done

if [[ $found = 0 ]]; then
    echo "type=dhcp-client"
fi

스크립트 이름을 지정하면 parse.sh다음과 같이 호출할 수 있습니다.

parse.sh < input.xml > output.txt

관련 정보