한 번의 클릭으로 여러 XML 파일의 모든 일치 항목을 수정하는 데 사용할 수 있는 bash 스크립트 또는 이와 유사한 스크립트를 작성하려고 합니다. 저는 24개의 XML 파일을 갖고 있는데, 각 파일에는 수십 개의 줄이 포함되어 있으며 Torque="SOMENUMBER"
각 파일에는 약 3-5번의 속성이 있습니다. 게임의 모든 모터에 토크를 25% 더 추가하기 위해 이를 1.25x 값으로 대체하고 싶습니다.
(모드와 게임 패치가 이를 무시하고 다른 값을 빠르게 시도할 수 있기 때문에 이는 유용합니다.)
숫자를 추출해서 변수에 넣는 아이디어 가 떠올랐는데 sed -n -e 's/Torque="\(.*\)"/\1/p' <filename.xml
, 어떻게 다시 올바른 위치에 넣는지 모르겠고, sed
위의 명령은 발생하는 모든 토크를 한 번에 출력합니다.
xmlstarlet은 내가 Google에서 검색한 내용을 기반으로 이 작업을 수행할 수 있지만 항상 xml 파일에 여러 루트 요소가 포함되어 있다고 불평합니다. 어쩌면 모든 것에 임시 태그를 추가하고 <root_temp><\root_temp>
xmlstarlet이 마법을 작동하게 한 다음 태그를 다시 제거하고 파일을 저장해야 할까요? Bash 스크립팅을 시작한 지 몇 년이 지났습니다. Python, cpp에서도 하고 싶습니다. 새로운 언어의 기본을 배우고 싶습니다. xD는 상관하지 않습니다.
XML 예:
<_templates>
<Engine>
<RUScoutModernEngine BrakesDelay="0.5" />
</Engine>
</_templates>
<EngineVariants>
<Engine
_template="RUScoutModernEngine"
CriticalDamageThreshold="0.7"
DamageCapacity="120"
DamagedConsumptionModifier="1.2"
EngineResponsiveness="0.35"
FuelConsumption="1.5"
Name="ru_scout_modern_engine_0"
Torque="70000"
DamagedMinTorqueMultiplier="1.0"
DamagedMaxTorqueMultiplier="0.6"
MaxDeltaAngVel="0.01"
>
<GameData
Price="1900"
UnlockByExploration="false"
UnlockByRank="1"
>
<UiDesc
PLACE="HOLDER"
/>
</GameData>
</Engine>
<Engine
BLA="BLA"
Torque="80000"
BLA="BLA"
>
<GameData
Price="5500"
UnlockByExploration="true"
UnlockByRank="1"
>
<UiDesc
PLACE="HOLDER"
/>
</GameData>
</Engine>
<Engine
BLA="BLA"
Torque="76000"
BLA="BLA"
>
<GameData
BLA="BLA"
>
<UiDesc/>
</GameData>
</Engine>
</EngineVariants>
답변1
손상된 XML 주위에 가짜 루트 노드를 추가하는 것은 매우 쉽고, 수정된 XML을 사용하는 것도 쉽고 , 수정 후에 추가된 루트 노드(및 추가된 루트 노드 ) xmlstarlet
를 제거하는 것도 그리 어렵지 않습니다 .<?xml version="1.0"?>
xmlstarlet
{ echo '<root>'; cat file.xml; echo '</root>'; } |
xmlstarlet ed -u '//Engine/@Torque' -x '. * 1.25' |
sed '1d; 2d; $d'
분명히 이는 이 비트에 의해 생성된 XML이 { ...; }
실제로 잘 구성된 XML 문서라고 가정합니다(예제 문서에 중복 속성이 있음).
위와 동일하지만 xq
(주변 XML 파서 의 일부로 jq
사용 가능) 을 사용합니다.yq
https://kislyuk.github.io/yq/):
{ echo '<root>'; cat file.xml; echo '</root>'; } |
xq -x '.root.EngineVariants.Engine[]."@Torque" |= ( tonumber * 1.25)' |
sed '1d; $d'
출력에는 xq
가 포함되어 있지 않습니다 <?xml version="1.0"?>
.
*.xml
xmlstarlet
위 코드의 변형을 예로 사용하여 이름이 일치하는 디렉터리의 모든 파일에 대해 이 작업을 반복합니다 .
tmpfile=$(mktemp)
for pathname in ./*.xml; do
cp "$pathname" "$tmpfile" &&
{ echo '<root>'; cat "$tmpfile"; echo '</root>'; } |
xmlstarlet ed -u '//Engine/@Torque' -x '. * 1.25' |
sed '1d; 2d; $d' >"$pathname"
done
rm -f "$tmpfile"
일치하는 파일은 위에서 그 자리에서 편집됩니다. 당신은 원할 수도 있습니다복사먼저, 파일입니다!
답변2
XML 조각(여러 루트 노드가 있는 파일)은 관리하기가 매우 어렵고 이를 직접 허용하는 도구는 거의 없습니다. 래핑 요소를 "수동으로" 추가하는 것도 좋은 생각입니다.
형식이 잘 지정된 문서가 있으면 xmlstarlet 또는 Saxon's Gizmo(https://saxonica.com/documentation10/index.html#!gizmo)는 단순한 [이기심의 진술]이어야 합니다. 기즈모에서는
update //@Torque with .*1.25
답변3
임시 루트 노드를 사용하여 옵션을 구현하여 작동하게 한 다음 제안된 대로 Gizmo를 사용하여 문제를 해결했습니다. 나중에 이 문제를 우연히 발견하는 사람을 위해 여기 내 해결책이 있습니다.
나는 자바 버전을 다운로드했다색슨 홈 에디션, "Saxon"이라는 하위 폴더에 압축을 풀고 다음 스크립트를 성공적으로 사용했습니다.
#!/bin/bash
#remove script and generate it with the following lines (that way I only need
#to include my one .sh file)
rm -f script
echo update //@Torque with .*1.25>script
echo save temp_updated.xml method=xml indent=yes>>script
#we do the following to all xml files in the subfolder "classes/engines/"
for filename in classes/engines/*.xml
do
#cleanup in case they got leftover, which is important for Gizmo,
#otherwise I get a thousand "Overwrite File" prompts, which is
#not conducive to automating the process.
rm -f temp.xml
rm -f temp_updated.xml
#make a new temp file, starting with the temporary root element,
#append the original file and close the root element
echo "<xml_temp>">temp.xml
cat $filename>>temp.xml
echo "</xml_temp>">>temp.xml
#call Saxon with the correct codepath, start the Gizmo subroutine or whatever
#take the temporary file as input and "script" as the commands to be executed
java -cp "Saxon/saxon-he-10.5.jar:Saxon/jline-2.14.6.jar" net.sf.saxon.Gizmo -s:temp.xml -q:script
#sed -i for inplace editing of the file
#the first expression '$d' removes the last line (the closing temp root tag)
#the second impression removes the first line (Gizmo tags on some kind of xml info
#and the second line, which contains the starting temp root tag
sed -i -e '$d' -e 1,2d temp_updated.xml
#I force overwrite the old file with the new and improved xml
cp -f temp_updated.xml $filename
#...and clean up after myself
rm -f temp.xml
rm -f temp_updated.xml
rm -f script
done