Nested sed (sed in sed) - bash

I want to extract the number of hostname (like Server01 => 01) and store this as a part of string into a file.
Unfortunatelly it still doesn't work. The last try looks like:
sed s/TRUNKNUMBER/0812345`hostname | sed -e 's/[^0-9]//g'`/ -i sipgate.xml
But the result is, TRUNKNUMBER is removed, instead replaced by number like '081234501'.
What did I wrong? Also I want to know how to count the chars if sed-error is given like
sed: -e expression #1, char 13: unknown option to `s'
UPDATE1:
Sure I can further informations. I thought it's clear, but sorry.
floh#Host01:~$ hostname
Host01
floh#Host01:~$ cat sipgate.xml
<extension name="sipgate">
<condition field="destination_number" expression="^TRUNKNUMBER">
...
</condition>
</extension>
</extension>
As I wrote I want to replace "TRUNKNUMBER" in sipgate.xml by a string concated by "0812345" + Number of Hostname.
With the one sed-command I can extract the number of hostname:
floh#Host01:~$ hostname | sed -e 's/[^0-9]//g'
01
This is fine, now I tried with:
sed s/TRUNKNUMBER/0812345`hostname | sed -e 's/[^0-9]//g'`/ -i sipgate.xml
Then I got:
floh#Host01:~$ cat sipgate.xml
<extension name="sipgate">
<condition field="destination_number" expression="^">
...
</condition>
</extension>
</extension>
Which is not good because I expected '...expression="^081234501">' in the second line.

Sorry, I found out the command was already ok:
sed s/TRUNKNUMBER/0812345`hostname | sed -e 's/[^0-9]//g'`/ -i sipgate.xml
The result was "wrong" because I acidentally reused the source-file which didn't had the string TRUNKNUMBER. (Obviously I forgot to restore the source-file for that try)
Now I learned that I should remove -i next time in order to test the output instead trying to modify the file.
Again I'm sorry!
Floh

Related

How to remove this special character at the end of the file

This is the output of cat command and I don't know what this special character is called that is at the end of the file to even search for. How to remove this special character in bash?
EDIT:
Here is the actual xml file(I am just copy pasting):
<?xml version="1.0" encoding="UTF-8"?>
<Package xmlns="http://soap.sforce.com/2006/04/metadata">
<types>
<name>ApexClass</name>
<members>CreditNotesManager</members>
<members>CreditNotesManagerTest</members>
</types>
<version>47.0</version>
</Package>%
It's unclear how the % (percent sign) is ending up in your file; it's easy to remove with sed:
sed -i '' 's/\(</.*>\)%.*/\1/g' file.xml
This will remove the percent and re-save your file. If you want to do a dry-run omit the -i '' portion as this is tells sed to save the file in-line.
As mentioned in the comments, there are many ways to do it. Just be sure you aren't removing something that you want to keep.
If it is just at the last line, this should work. Using ed(1)
printf '%s\n' '$s/%//' w | ed -s file.xml
If you don't need to save changes, you could use grep:
grep -v "%" <file.xml
This uses grep along with it's inverse matching flag -v. This method will remove all instances of the character % and print the result to STOUT. The < character is a method to tell grep which file you're talking about.
EDIT: actually you don't even need the redirection, so:
grep -v "%" file.xml
This is actually a feature of zsh, not bash.
To disable it, unsetopt prompt_cr prompt_sp
The reverse prompt character showing up means that line had an end-of-file before a final ascii linefeed (newline) character.
How to remove this special character at the end of the file

Bash change number to another value on specific line

i'm new with bash scripting , and i looking for solution to change a number to another value on specific line.
I have file named foo.config and in this file i have about 100 lines of configuration.
For example i have
<UpdateInterval>2</UpdateInterval>
and i need to find this line on foo.config and replace number(this can be number for 0 to 10 and for my example is 2) for 0 as always.
Like this :
<UpdateInterval>0</UpdateInterval>
How can i do it with sed ? please suggest
the part of lines:
<InstallUrl />
<TargetCulture>en</TargetCulture>
<ApplicationVersion>1.0.1.8</ApplicationVersion>
<AutoIncrementApplicationRevision>true</AutoIncrementApplicationRevision>
<UpdateEnabled>true</UpdateEnabled>
<UpdateInterval>2</UpdateInterval>
<UpdateIntervalUnits>hours</UpdateIntervalUnits>
<ProductName>xxxxxxxxxxxx</ProductName>
<PublisherName />
<SupportUrl />
<FriendlyName>xxxxxxxxxxxx</FriendlyName>
<OfficeApplicationDescription />
<LoadBehavior>3</LoadBehavior>
sed and others(grep, awk) never be a good tools for parsing xml/html data. Use a proper xml/html parsers, like xmlstarlet:
xmlstarlet ed -L -O -u "//UpdateInterval" -v 0 foo.config
ed - edit mode
-L - edit the file inplace
-O - omit xml declaration
-u - update action
"//UpdateInterval" - xpath expression
-v 0 - the new value of the element to be updated
The final (exemplary) foo.config contents:
<root>
<InstallUrl/>
<TargetCulture>en</TargetCulture>
<ApplicationVersion>1.0.1.8</ApplicationVersion>
<AutoIncrementApplicationRevision>true</AutoIncrementApplicationRevision>
<UpdateEnabled>true</UpdateEnabled>
<UpdateInterval>0</UpdateInterval>
<UpdateIntervalUnits>hours</UpdateIntervalUnits>
<ProductName>xxxxxxxxxxxx</ProductName>
<PublisherName/>
<SupportUrl/>
<FriendlyName>xxxxxxxxxxxx</FriendlyName>
<OfficeApplicationDescription/>
<LoadBehavior>3</LoadBehavior>
</root>
The <root> tag was specified for demonstration purpose, your xml/html structure should have its own "root"(most parent) tag
In a very simple way, you may try:
sed -E 's/^<UpdateInterval>[0-9]+/<UpdateInterval>0/' foo.config
This will search for <UpdateInterval> at the beginning of a line (note the ^) and then a number ([0-9] stands for a digit and + for a repetition of one or more). This bit will be replaced with <UpdateInterval>0. The / characters separate what you search and what will replace it. The s command is a search and replace.
It will take the file foo.config as input and you will get the output on standard output. If you want your output on the same file, you may do:
sed -E 's/^<UpdateInterval>[0-9]+/<UpdateInterval>0/' foo.config >foo.temp
mv foo.temp foo.config
Or more simply:
sed -i -E 's/^<UpdateInterval>[0-9]+/<UpdateInterval>0/' foo.config
Note that this is not a good way to do the substitution if your config file contains general XML. It will only work in the simplest of cases (but will do for your example.) If your XML bit may be in the middle of a line, remove the ^ character. The search and replace expression assumes that there is no whitespace around the XML tags.
A solution using an XML parsing tool:
{ echo '<root>'; cat foo.config; echo '</root>'; } |
xmlstarlet ed -O -P -u //UpdateInterval -v 0 |
sed '1d;$d' |
sponge foo.config
The first line is to make the config file into a proper XML file.
The second line updates the value.
The third line removes the root tags.
The last line rewrites the config file. Need to install the moreutils package.

Getting bad flag in substitute command '/' using sed replacement with custom string

I'm using macOS Sierra, and I'm and trying to manipulate a value of a key from a config file.
In order to achieve that I'm using (which works fine for simple values):
sed -i .bak "/^$KEY/s/\(.[^=]*\)\([ \t]*=[ \t]*\)\(.[^=]*\)/\1\2$VALUE/" $CONFIG_FILE
Unfortunately, my string $VALUE is quite complex with many special characters, giving me the error:
bad flag in substitute command: '/'
My $VALUE is being declared as:
VALUE='<Request xmlns="urn:oasis:names:tc:xacml:3.0:core:schema:wd-17" ReturnPolicyIdList="false" CombinedDecision="false"> <Attributes Category="urn:oasis:names:tc:xacml:3.0:attribute-category:resource"> <Attribute IncludeInResult="false" AttributeId="urn:oasis:names:tc:xacml:1.0:resource:resource-id"> <AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">test </AttributeValue> </Attribute> </Attributes> <Attributes Category="urn:oasis:names:tc:xacml:3.0:attribute-category:action"> <Attribute IncludeInResult="false" AttributeId="urn:oasis:names:tc:xacml:1.0:action:action-id"> <AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">testing something</AttributeValue> </Attribute> </Attributes> </Request>'
Since I have double quotes being part of the value of $VALUE, I can't use double quotes instead of single quote when declaring it... Any ideas to workaround this?
The problem is that $VALUE contains slashes which should be escaped because it conflicts with the separator for the substiture command
That's not convenient because if it changes, you have to escape them again. That's a solution, nevertheless.
Another simpler solution is to use an alternate separating character for s command which isn't in the $VALUE string, like % for instance (% has less chance to be in such a string, otherwise | can also be used).
sed -i .bak "/^$KEY/s%\(.[^=]*\)\([ \t]*=[ \t]*\)\(.[^=]*\)%\1\2$VALUE%" $CONFIG_FILE
or with pipe:
sed -i .bak "/^$KEY/s|\(.[^=]*\)\([ \t]*=[ \t]*\)\(.[^=]*\)|\1\2$VALUE|" $CONFIG_FILE

replace one attribute on another with sed or awk

<testcase classname='tc1' name='tc1' time='78.455094'/>
<testcase classname='tc2' name='tc2' time='78.549320'>
<failure type='fail-verdict'>
error message
</failure>
</testcase>
<testcase classname='tc3' name='tc_3' time='78.444719'/>
how to replace 3-rd attribute time in testcase tag to attribute status (status="pass" or "failure" based on testcase; for example: tc1,tc3 - pass, tc2- fail). I tried sed: sed -i 's/time=\'[0-9]+\.[0-9]+'/status="pass"/g' file.txt firstly without any logic..but it doesn't work.
You need the -E option (and -r for gnu sed) to use ERE (+ and more) or you should use [0-9][0-9]*
You cannot escape singlequotes inside single quotes, you need to do the following:
% echo 'hello'\'' world'
hello' world
Applied to your command:
sed -i 's/time='\''[0-9][0-9]*\.[0-9][0-9]*'\''/status="pass"/g' file.txt

Shellscript Read XML attribute value

We want to read XML attributes from an XML file. Example of file content is as below:
<properties>
<property name="abc" value="15"/>
<property name="xyz" value="26"/>
</properties>
We want to read value (i.e. 15) for property "abc" using shell script.
Please suggest shell commands to achieve this.
You can use a proper XML parser like xmllint. If your version supports xpath, it will be very easy to grab specific values. If it doesn't support xpath, then you can use --shell option like so:
$ echo 'cat //properties/property[#name="abc"]/#value' | xmllint --shell myxml
/ > -------
value="15"
/ >
You can then use awk or sed to format and extract desired field from output.
$ echo 'cat //properties/property[#name="abc"]/#value' | xmllint --shell myxmlfile | awk -F'[="]' '!/>/{print $(NF-1)}'
15
You can use command substitution to capture the output in a variable by saying:
$ myvar=$(echo 'cat //properties/property[#name="abc"]/#value' | xmllint --shell myxml | awk -F'[="]' '!/>/{print $(NF-1)}')
$ echo "$myvar"
15
Using anything else other than a xmlparser is prone to errors and will break easy.
quick and dirty
sed -n '/<Properties>/,\|</properties>| {
s/ *<property name="xyz" value="\([^"]*\)"\/>/\1/p
}'
no xml check and based on your sample so assume same structure (one property name per line, ...)
posix version (--posix for GNU sed)
sed -n '/<property name="abc"/s/.*value="\(.*\)"[^\n]*/\1/p' file
Creates a hold pattern for the value then matches everything except for the newline to avoid printing the newline, it expects the value double quoted as per your example data.
E.g.
<properties>
<property name="abc" value="15"/>
<property name="xyz" value="26"/>
</properties>
Output:
15
(Prior to edit: sed '/<property name="abc"/s/.*value="\(.*\)"[^\n]*/\1/' file)

Resources