I have an xml file which looks like below
<name>abcdefg</name>
<value>123456</value>
I am trying to write a script using sed to search for the tag "abcdefg" and then replace the corresponding value "123456" but unfortunately I am not able to find a logic to achieve above.
Need help!
Sample data used:
cat key
<name>abcdaaefg</name>
<value>123456</value>
<name>abcdefg</name>
<value>123456</value>
<name>abcdaaefg</name>
<value>123456</value>
sed solution:
sed '/abcdefg/!b;n;c<value>OLA<value>' key
<name>abcdaaefg</name>
<value>123456</value>
<name>abcdefg</name>
<value>OLA<value>
<name>abcdaaefg</name>
<value>123456</value>
For doing changes in file.
sed -i.bak '/abcdefg/!b;n;c<value>OLA<value>' key
awk Solution:
awk '/abcdefg/ {print $0;getline;sub(/>.*</,">ola<")} {print $0}' key
<name>abcdaaefg</name>
<value>123456</value>
<name>abcdefg</name>
<value>ola</value>
<name>abcdaaefg</name>
<value>123456</value>
Search for a line containing abcdefg and then do following actions:
1. print that line,
2.move to next line and replace the value inside html tag to something else. Here , I have replaced 123456 with ola.
Whenever you have tag->value pairs in your data it's a good idea to create a tag->value array in your code:
$ awk -F'[<>]' '{tag=$2; v[tag]=$3} tag=="value" && v["name"]=="abcdefg" {sub(/>.*</,">blahblah<")} 1' file
<name>abcdefg</name>
<value>blahblah</value>
Use an XML-aware tool. This will make your approach far more robust: It means that tiny changes in the textual description (like added or removed newlines, or extra attributes added to a preexisting element) won't break your script.
Assuming that your input's structure looks like this (with being under a single parent item, here called item, defining the relationship between a name and a value):
<config>
<item><name>abcdef</name><value>123456</value></item>
<item><name>fedcba</name><value>654321</value></item>
</config>
...you can edit it like so:
# edit the value under an item having name "abcdef"
xmlstarlet ed -u '//item[name="abcdef"]/value' -v "new-value"
If instead it's like this (with ordering between name/value pairs describing their relationship):
<config>
<name>abcdef</name><value>123456</value>
<name>fedcba</name><value>654321</value>
</config>
...then you can edit it like so:
# update the value immediately following a name of "abcdef"
xmlstarlet ed -u '//name[. = "abcdef"]/following-sibling::value[1]' -v new-value
Related
I am struggling to write a bash script or python script to find a string from a file.
For example, I need to search for usrname4 and if it found then I need fetch its group. In this case, it is group1. Since the file format is tricky i am looking after some hints.
The file contents are in below format.
group1 (-,usrname1,abc.co.uk)\
(-,usrname1,xyz.co.uk)\
(-,usrname2,abc.co.uk)\
(-,usrname2,xyz.co.uk)\
(-,usrname3,abc.co.uk)\
(-,usrname3,xyz.co.uk)\
(-,usrname4,abc.co.uk)\
(-,usrname4,xyz.co.uk)\
(-,usrname5,abc.co.uk)\
(-,usrname5,xyz.co.uk)\
(-,usrname6,abc.co.uk)\
(-,usrname6,xyz.co.uk)\
(-,usrname7,abc.co.uk)\
(-,usrname7,xyz.co.uk)\
group2 (-,usrname8,abc.co.uk)\
(-,usrname8,xyz.co.uk)\
(-,usrname9,abc.co.uk)\
(-,usrname9,xyz.co.uk)\
(-,usrname10,abc.co.uk)\
(-,usrname10,xyz.co.uk)\
(-,usrname11,abc.co.uk)\
(-,usrname11,xyz.co.uk)\
(-,usrname12,abc.co.uk)\
(-,usrname12,xyz.co.uk)\
(-,usrname13,abc.co.uk)\
(-,usrname13,xyz.co.uk)\
(-,usrname14,abc.co.uk)\
(-,usrname14,xyz.co.uk)\
I added the following specifications:
A group can be found by looking for the a line that starts without a space
A group name is without spaces
When username occurs more than once, only look at the first one
Search for the last group mentioned before the match
First select all groups and all matched lines.
From that set look for the last line before the first match, that must be the group.
usr=usrname4
grep -Eo "^[^ ]+|,${usr}," file | grep -B1 ",${usr}," | head -1
I'm trying to parse the output of git config --list to get a list of key/value pairs. For simple variables like user.name e.g.
user.name=John Doe
it seems like I can just split the line on '=' to get the key and value. However, after looking into the syntax, it appears that a key can contain any value in a subsection (including '='), and a value can contain a '=' or a '.'. So how do I reliably parse the output of git config --list to get key/value pairs?
Also, I wonder if running git -c key=value <comecommand> will always work with key/value containing '=' or '.'.
If you have Bash4+ you can parse key=value pairs from the git config into an associative array:
#!/usr/bin/env bash
declare -A git_config
# Parse git config into an associative array
while IFS='=' read -r k v; do
git_config["$k"]="$v"
done < <(git config --list)
# Print-out of the parsed config
printf '%-40s %s\n' 'Git config keys' 'Values'
printf '=%.0s' {1..120}
echo
for k in "${!git_config[#]}"; do
printf '%-40q %q\n' "$k" "${git_config["$k"]}"
done
Here's an example of what I am trying to do:
mydictionary={
'apple': 'crunchy fruit',
'banana': 'mushy and yellow'
}
rule all:
input:
expand('{key}.txt', key=mydictionary.keys())
rule test:
output: temp('{f}.txt')
shell:
"""
echo {mydictionary[wildcards.f]} > {output}
cat {output}
"""
For some reason, I am not able to access the dictionary contents. I tried using double-curly brackets, but the content of the text files becomes literal {mydictionary[wildcards.f]} (while I want the content of the corresponding entry in the dictionary).
I'm pretty sure the bracket markup can only replace variables with string representations of their values, but does not support any code evaluation within the brackets. That is, {mydictionary[wildcards.f]} will try to look up a variable literally named "mydictionary[wildcards.f]". Likewise, {mydictionary}[{wildcards.f}] will just paste the string values together. So, I don't think you can do what you want within the shell section alone. Instead, you can accomplish what you want in the params section:
rule test:
output: temp('{f}.txt')
params:
value=lambda wcs: mydictionary[wcs.f]
shell:
"""
echo '{params.value}' > {output}
cat {output}
"""
for key in dictionary:
file = file.replace(str(key), dictionary[key])
With this simple snippet I am able to replace each occurence of dictionary key, with it's value, in a file. (Python)
Is there a similar way to go about in bash?
Exampple:
file="addMesh:"0x234544"
addMesh="0x12353514"
${!dictionary[i]}: 0x234544
${dictionary[i]}: 0x234544x0
${!dictionary[i]}: 0x12353514
${!dictionary[i]}: 0x12353514x0
Wanted output (new content of file):"addMesh:"0x234544x0"
addMesh="0x12353514x0"
:
for i in "${!dictionary[#]}"
do
echo "key : $i"
echo "value: ${dictionary[$i]}"
echo
done
While there certainly are more sophisticated methods to do this, I find the following much easier to understand, and maybe it's just fast enough for your use case:
#!/bin/bash
# Create copy of source file: can be omitted
cat addMesh.txt > newAddMesh.txt
file_to_modify=newAddMesh.txt
# Declare the dictionary
declare -A dictionary
dictionary["0x234544"]=0x234544x0
dictionary["0x12353514"]=0x12353514x0
# use sed to perform all substitutions
for i in "${!dictionary[#]}"
do
sed -i "s/$i/${dictionary[$i]}/g" "$file_to_modify"
done
# Display the result: can be omitted
echo "Content of $file_to_modify :"
cat "$file_to_modify"
Assuming that the input file addMesh.txt contains
"addMesh:"0x234544"
addMesh="0x12353514"
the resulting file will contain:
"addMesh:"0x234544x0"
addMesh="0x12353514x0"
This method is not very fast, because it invokes sed multiple times. But it does not require sed to generate other sed scripts or anything like that. Therefore, it is closer to the original Python script. If you need better performance, refer to the answers in the linked question.
There is no perfect equivalent in Bash. You could do it in a roundabout way, given that dict is the associative array:
# traverse the dictionary and build command file for sed
for key in "${!dict[#]}"; do
printf "s/%s/%s/g;\n" "$key" "${dict[$key]}"
done > sed.commands
# run sed
sed -f sed.commands file > file.modified
# clean up
rm -f sed.commands
I am using Jenkins python api to create a parameterized job, I can create a job with one parameter using the following config.xml
<?xml version='1.0' encoding='UTF-8'?>
<project>
<actions/>
<description>A build that explores the wonderous possibilities of parameterized builds.</description>
<keepDependencies>false</keepDependencies>
<properties>
<hudson.model.ParametersDefinitionProperty>
<parameterDefinitions>
<hudson.model.StringParameterDefinition>
<name>B</name>
<description>B, like buzzing B.</description>
<defaultValue></defaultValue>
</hudson.model.StringParameterDefinition>
</parameterDefinitions>
</hudson.model.ParametersDefinitionProperty>
</properties>
<scm class="hudson.scm.NullSCM"/>
<canRoam>true</canRoam>
<disabled>false</disabled>
<blockBuildWhenDownstreamBuilding>false</blockBuildWhenDownstreamBuilding>
<blockBuildWhenUpstreamBuilding>false</blockBuildWhenUpstreamBuilding>
<triggers class="vector"/>
<concurrentBuild>false</concurrentBuild>
<builders>
<hudson.tasks.Shell>
<command>ping -c 1 localhost | tee out.txt
echo $A > a.txt
echo $B > b.txt</command>
</hudson.tasks.Shell>
</builders>
<publishers>
<hudson.tasks.ArtifactArchiver>
<artifacts>*</artifacts>
<latestOnly>false</latestOnly>
</hudson.tasks.ArtifactArchiver>
<hudson.tasks.Fingerprinter>
<targets></targets>
<recordBuildArtifacts>true</recordBuildArtifacts>
</hudson.tasks.Fingerprinter>
</publishers>
<buildWrappers/>
</project>
What I really want is to create a job with multiple parameters, I have tried adding a paralleled <name> tag in this xml, but it actually make one parameter in a new job. Do I change the xml mistakenly?
What's more, is it possible to add predefined values in parameter fields in the api? For example, the parameter B would have a value b after job creation.
Each parameter needs its own hudson.model.StringParameterDefinition section. It sounds like you're trying to put multiple names inside one StringParameterDefintion section, which won't work.
If in doubt, create the job by hand, then go to the page for that job and append '/config.xml'. You will get back the XML for the job. Get your Python to replicate that, and you're all set.