sed delete multiple lines - sed

I have little problem with deleting multiple lines with sed. I read a lot of guides and discussions, but none of them helped. I have a xml file, and I need to delete more occurences of these three lines:
<function type="class">
<arg name="class.name">com.mycompany.name.UnLockIssueFunction</arg>
</function>
I wanted to use deleting just the part between <function>, but there is more of this tags. My xml file looks like this
<post-functions>
<function type="class">
<arg name="class.name">com.mycompany.name.function.issue.UpdateIssueStatusFunction</arg>
</function>
<function type="class">
<arg name="class.name">com.mycompany.name.function.misc.CreateCommentFunction</arg>
</function>
<function type="class">
<arg name="class.name">com.mycompany.name.function.issue.GenerateChangeHistoryFunction</arg>
</function>
<function type="class">
<arg name="class.name">com.mycompany.name.function.issue.IssueReindexFunction</arg>
</function>
<function type="class">
<arg name="class.name">com.mycompany.name.function.event.FireIssueEventFunction</arg>
<arg name="eventTypeId">13</arg>
</function>
<function type="class">
<arg name="class.name">com.mycompany.name.UnLockIssueFunction</arg>
</function>
</post-functions>

This might work for you (GNU sed):
sed '/<function type="class">/!b;N;N;/<function type="class">\s*\n\s*<arg name="class.name">com.mycompany.name.UnLockIssueFunction<\/arg>\s*\n\s*<\/function>/d' file

When you get into fancier editing, fancier editors may help. Try reading up on scripting in VIM and take a look at these questions:
Search and delete multiple lines
VIM: globally match line, delete this and 2 following lines

Related

Raspberry Pi + Bluez + A2DP + AVRCP

In the past 2 days i've been googling for a way to control the media playback from my iPhone through my Raspiberry pi headless speaker.
I've successfully setup the pi using the following tutorial:
Headless A2DP Audio Streaming on Raspbian Stretch
and now i'm looking for a way to control the playback of the audio stream from my raspberry pi.
I've been looking into MediaTransport1, MediaPlayer1, MediaControl1 but unfortunately i wasn't successful.
to give you a few examples of the trial and error I've performed:
for:
dbus-send --system --print-reply --dest=org.bluez /org/bluez/hci0/dev_C8_85_50_B1_C8_6B org.bluez.MediaPlayer1.Pause
i received:
Error org.freedesktop.DBus.Error.UnknownMethod: Method "Pause" with signature "" on interface "org.bluez.MediaPlayer1" doesn't exist
for
qdbus --system org.bluez /org/bluez/hci0/dev_C8_85_50_B1_C8_6B/fd0 org.freedesktop.DBus.Properties.Set org.bluez.MediaTransport1 Volume 127
i received
Error: org.freedesktop.DBus.Error.InvalidSignature
Invalid signature for 'Volume'
Additionally, i've found a player that i thought i could use to build my own script as an example Here but i've got an error:
pi#raspberrypi:~/blueutils $ python simpleplayer.py
Available commands:
PropertiesChanged(interface, properties)
help(cmd)
Use python syntax to pass arguments to available methods.
E.g.: PropertiesChanged({'Metadata' : {'Title': 'My title', 'Album': 'my album' }})
>>> <Interface <ProxyObject wrapping <dbus._dbus.SystemBus (system) at 0xb61968d0> :1.13 /org/bluez/hci0 at 0xb619db70> implementing 'org.bluez.Media1' at 0xb619dc50>
Traceback (most recent call last):
File "simpleplayer.py", line 197, in <module>
media.RegisterPlayer(dbus.ObjectPath(path), player.properties)
File "/usr/lib/python2.7/dist-packages/dbus/proxies.py", line 70, in __call__
return self._proxy_method(*args, **keywords)
File "/usr/lib/python2.7/dist-packages/dbus/proxies.py", line 145, in __call__
**keywords)
File "/usr/lib/python2.7/dist-packages/dbus/connection.py", line 651, in call_blocking
message, timeout)
dbus.exceptions.DBusException: org.bluez.Error.NotSupported: Operation is not supported
when i do an introspect
dbus-send --system --print-reply --dest=org.bluez /org/bluez/hci0 org.freedesktop.DBus.Introspectable.Introspect
i get his:
<node>
<interface name="org.freedesktop.DBus.Introspectable">
<method name="Introspect">
<arg name="xml" type="s" direction="out"/>
</method>
</interface>
<interface name="org.bluez.Adapter1">
<method name="StartDiscovery"></method>
<method name="SetDiscoveryFilter">
<arg name="properties" type="a{sv}" direction="in"/>
</method>
<method name="StopDiscovery"></method>
<method name="RemoveDevice">
<arg name="device" type="o" direction="in"/>
</method>
<property name="Address" type="s" access="read"></property>
<property name="Name" type="s" access="read"></property>
<property name="Alias" type="s" access="readwrite"></property>
<property name="Class" type="u" access="read"></property>
<property name="Powered" type="b" access="readwrite"></property>
<property name="Discoverable" type="b" access="readwrite"></property>
<property name="DiscoverableTimeout" type="u" access="readwrite"></property>]
<property name="Pairable" type="b" access="readwrite"></property>
<property name="PairableTimeout" type="u" access="readwrite"></property>
<property name="Discovering" type="b" access="read"></property>
<property name="UUIDs" type="as" access="read"></property>
<property name="Modalias" type="s" access="read"></property>
</interface>
<interface name="org.freedesktop.DBus.Properties">
<method name="Get">
<arg name="interface" type="s" direction="in"/>
<arg name="name" type="s" direction="in"/>
<arg name="value" type="v" direction="out"/>
</method>
<method name="Set">
<arg name="interface" type="s" direction="in"/>
<arg name="name" type="s" direction="in"/>
<arg name="value" type="v" direction="in"/>
</method>
<method name="GetAll">
<arg name="interface" type="s" direction="in"/>
<arg name="properties" type="a{sv}" direction="out"/>
</method>
<signal name="PropertiesChanged">
<arg name="interface" type="s"/>
<arg name="changed_properties" type="a{sv}"/>
<arg name="invalidated_properties" type="as"/>
</signal>
</interface>
<interface name="org.bluez.GattManager1">
<method name="RegisterApplication">
<arg name="application" type="o" direction="in"/>
<arg name="options" type="a{sv}" direction="in"/>
</method>
<method name="UnregisterApplication">
<arg name="application" type="o" direction="in"/>
</method>
</interface>
<interface name="org.bluez.Media1">
<method name="RegisterEndpoint">
<arg name="endpoint" type="o" direction="in"/>
<arg name="properties" type="a{sv}" direction="in"/>
</method>
<method name="UnregisterEndpoint">
<arg name="endpoint" type="o" direction="in"/>
</method>
<method name="RegisterPlayer">
<arg name="player" type="o" direction="in"/>
<arg name="properties" type="a{sv}" direction="in"/>
</method>
<method name="UnregisterPlayer">
<arg name="player" type="o" direction="in"/>
</method>
</interface>
<node name="dev_40_9C_28_07_63_DD"/>
<node name="dev_C8_85_50_B1_C8_6B"/>
</node>
Can anybody help me figure this issue out, or does anybody know a procedure to control the playback of the music on the phone, using the raspberry pi ?
Regards.
Update 1:
Thank you so much #Parthiban for it works perfectly.
Additionally, i have to say that i reinstalled the bluez version to 5.50 by following the tutorial here: Install bluez on the Raspberry Pi as i wasn't able to see /playerX (0 in my case). Before i compiled the sources, i did a little extra (not sure it's relevant but it doesn't hurt), i added the .auto_connect = true
the the avrcp profiles as indicated :
Here
hope this helps everybody that may face my problem
You need to specify the signature to set the volume as below,
dbus-send --system --print-reply --type=method_call --dest='org.bluez' '/org/bluez/hci0/dev_C8_85_50_B1_C8_6B/fd0' org.freedesktop.DBus.Properties.Set string:"org.bluez.MediaTransport1" string:"Volume" variant:uint16:127
This is because, as mentioned in dbus specification you need to specify three arguments when using set,
Interface Name
Property Name
Property value as variant
For the pause method, explore the "org.bluez.MediaPlayer1" interface of your device using "org.freedesktop.DBus.Introspectable.Introspect". The object path which you have used to access the method "Pause" is wrong. As stated here, you need to use "[variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX/playerX".
So in your case, it should be,
dbus-send --system --print-reply --type=method_call --dest='org.bluez' '/org/bluez/hci0/dev_C8_85_50_B1_C8_6B/playerX' org.bluez.MediaPlayer1.Pause
Where playerX needs to be replaced by your device player (you can get that from Introspect or watch on "InterfaceAdded" Signal.

In NAnt <exec>, how to have a conditional <arg> based on property value?

I've got an NAnt <exec> task. I want one argument presence to be conditional to some property being true.
For example, I want the -c command line argument of psExec to be conditional. It should be outputted only if ${pExec.copyprog == 'true'}.
The following does not work:
<property name="psExec.copyprog" value="false" />
...
<exec program="${psExec.path}" failonerror="false">
...
<arg line="-c" if="${psExec.copyprog}==true" />
</exec>
It yields the following error:
'false==true' is not a valid value for attribute 'if' of <arg ... />.
Cannot resolve 'false==true' to boolean value.
String was not recognized as a valid Boolean.
How can I achieve this?
Properties in NAnt are tricky since they don't have a type and simply are considered as of type string. So this would be the solution:
<exec program="${psExec.path}" failonerror="false">
<!-- ... -->
<arg line="-c" if="${bool::parse(psExec.copyprog)}" />
</exec>
Update: Mea culpa! I was wrong. if="${psExec.copyprog}" does also work. So there is some sort of property typing.
You'd need to put ==true inside {}, but you can also just skip it:
<arg line="-c" if="${psExec.copyprog}" />
Comparing a true boolean expression to true does not change the result.

How to replace string in a file using NANT?

I am trying to replace the occurance of a string in a wxs file using Nant.
I have only found the following example, which uses <replaceString>, but it seems like it can only be used within the copied files. Are there any other way of replacing a string, without actually copying the files over?
<property name="NOW" value="${datetime::now()}" />
<copy todir="out">
<fileset basedir="in">
<include name="**/*" />
</fileset>
<filterchain>
<replacetokens>
<token key="NOW" value="${TODAY}" />
</replacetokens>
<tabstospaces />
</filterchain>
</copy>
Here's the code:
<loadfile file="token.txt" property="token-file">
<filterchain>
<replacetokens>
<token key="NOW" value="${datetime::now()}" />
</replacetokens>
</filterchain>
</loadfile>
The official NAnt docs for <loadfile> element contain the exact sample you need. See the bottom of the page.
Here's how I did it.
<loadfile file="${file}" property="file.content">
<filterchain>
<replacestring from="StringToMatch" to="StringToReplace" ignorecase="true" />
</filterchain>
</loadfile>
<echo file="${file}">${file.content}</echo>
So you are trying to modify a .wxs file which is XML, right?
In this particular case you might use <xmlpoke> if you are able to determine the position of the strings to replace via XPath.
I found a solution for you here: http://frank.overseakids.com/?p=182
<loadfile file=”${dir.template}\template.db_name.sql” property=”restore.db.sql.db_name”>
<filterchain>
<replacetokens>
<!– this looks for tokens like #blah.blah# in the file being loaded and replaces them–>
<token key=”restore.db.prefix” value=”${restore.db.prefix}” />
<token key=”backup.file.path” value=”${backup.file.path}” />
</replacetokens>
</filterchain>
</loadfile>
<property name=”current.db” value=”db_name” />
<property name=”current.log” value=”${dir.log}\${restore.db.logfile.prefix}_db_name.log” />
<property name=”current.file” value=”${dir.template}\restore.db_name.tmp.sql” />
<delete if=”${file::exists(current.file)}” file=”${current.file}” />
<echo file=”${current.file}”>${restore.db.sql.db_name}</echo>
You can wrap this in a <foreach /> element.
I never managed to get the filterchain and replacetokens to work properly. I ended up using this and it works great.
<replacetext filename="${filename}" src="stringToBeReplaced" replacement="replacementString" />
All these answers did not work for me, maybe because I needed to replace a string with spaces in it. Loading a file content with filterchain/replacetokens did nothing to the contents of the associated property. Maybe I'm using it wrong.
The tasks "replacestring" and "replacetext" suggested by #Ally and #John Sterne do not exist.
It's included in a Jenkins build process, thus the ENVIRONMENT variable must be set to the working dir.
<loadfile file="./my/batch.bat" property="file.content" />
<property name="file.content"
value="${string::replace(file.content, 'D:\path to\the working\space', environment::get-variable('WORKSPACE'))}" />
<property name="file.content"
value="${string::replace(file.content, 'Cd C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin', 'CD /D C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin')}" />
<echo file="./my/batch.bat">${file.content}</echo>
I had that problem today. To solve it I used the move command instead of loadfile or copy. This worked for me because since my file was pretty small. The other caution about this is that replacetokens needs a start identifier and end identifier of the token; begintoken and endtoke respectively. If those are not set the default values are the # symbol. So if you want to replace a value such as MY_SERVER_PLACE_HOLDER that means the value in your file must be #MY_SERVER_PLACE_HOLDER#. If you want your token to start with something different than you should specify the begintoken and endtoken values. That should give you an idea of the problems the begin token and endtoken will bring you.
So here is what I did in a nutshell
Moved the file to a temporary location. In that move I used
filterchain with removetokens to change the values in the file.
In step 2, I moved the file back to it's original location.
I then used the delete command to delete the temp folder I created.
Here is a what I did. (May not be syntactically correct since I am not in front of the code at the moment)
<move todir="temp">
<fileset basedir="in">
<include name="myfile.dat" />
</fileset>
<filterchain>
<replacetokens>
<token key="MY_SERVER_PLACE_HOLDER" value="http://www.someserver.com" />
</replacetokens>
<tabstospaces />
</filterchain>
</move>
<move todir="in">
<fileset basedir="temp">
<include name="myfile.dat" />
</fileset>
</move>
<delete dir="temp" />

Convert long name to short name in NANT?

I am working on a NANT build project to build a VS project. One of the build file has a property definition like this:
<property name="App.dir"
value ="${directory::get-current-directory()}\Source\App"/>
This property value has been used in many other places. For example:
<exec program=".\test.exe" workingdir=".">
<arg line="${App.dir}\project1\resources\res1.resx /arg2"/>
Here I need to use <arg line=...> instead of <arg value=...> is to pass specified 2 arguments to text.exe.
when I build this NANT project on another developer's machine, I got a build failure. Finally I found out that the ${App.dir} on that developer's machine is a path in long-form and there is a space in the path. As a result, the arguments to text.exe were actually 3 or more.
I am not sure if there is any way to convert the ${App.dir} path to short name with no spaces:
<property name="App.dir" value ="????"/>
where ???? is something to convert "${directory::get-current-directory()}\Source\App" to a path name in a short-form. Is there any way to do that?
I am using NANT in Windows XP. In Unix/Cgywin, there is one function to get dos name:
cygpath::get-dos-path
Can I use this one in my NANT build file?
Use <arg value="">, from the NANT docs:
value - A single command-line argument; can contain space characters.
I think that I found two ways to resolve the issue. Instead of converting path to DOS path (8.3 name), I can use quotes around my arguments. The second method is the one as ovado recommened to use <arg value=.../> for a single argument value. Here is my test example. All the test files are in my C:\Test folder. First, I created a test bat:
#REM This is the content of Test.bat file.
#echo COMMAND PARAMETERS: %*
#echo FIRST PARAMETER: %1
#echo SECOND PARAMETER: %2
dir %1
Then I created a test build file (Test.Build)"
<project>
<target name="Test" description="Test with one line" failonerror="true">
<property name="App.dir" value ="C:\Program Files"/>
<exec program="test.bat" workingdir=".">
<arg line='"${App.dir}\Microsoft*.*" ${App.dir}\test2 /test3' />
</exec>
</target>
<target name="Test2" description="Test2 with values" failonerror="true">
<property name="App.dir" value ="C:\Program Files"/>
<exec program="test.bat" workingdir=".">
<arg value="${App.dir}\Microsoft*.*" />
<arg value="${App.dir}\test2" />
<arg value="/test3" />
</exec>
</target>
</project>
Here I used " to close my first argument in <arg ='"..."' .../>. Notice that I used single quote for my attribute line.
In this way, I run my build by NANT.EXE. I got the result as I expected:
C:\Test>NANT.exe -buildfile:test.build Test
Test:
[exec] COMMAND PARAMETERS: "C:\Program Files\Microsoft*.*" C:\Program Files\test2 /test3
[exec] FIRST PARAMETER: "C:\Program Files\Microsoft*.*"
[exec] SECOND PARAMETER: C:\Program
[exec] C:\Test\>dir "C:\Program Files\Microsoft*.*"
[exec] Volume in drive C has...
....
I got the same result with the alternative Test2,
C:\Test>NANT.exe -buildfile:test.build Test2
...

Nant: Find file by pattern

What I am trying to do, is to find a file with NAnt. This file could by anywhere in a directory structure of a given folder.
I tried to this with the NAnt-foreach task (this works) but I am not quite convinced of that:
<target name="find-file">
<fail message="Property param.dir must be set" unless="${property::exists('param.dir')}" />
<fail message="Property param.pattern must be set" unless="${property::exists('param.pattern')}" />
<property name="return.file" value="" />
<foreach item="File" property="iterator.file">
<in>
<items>
<include name="${param.dir}\**\${param.pattern}" />
</items>
</in>
<do>
<property name="return.file" value="${iterator.file}" if="${string::get-length(return.file) == 0}" />
</do>
</foreach>
</target>
Is there anybody aware of a better approach? If not how can I accomplish to exit the foreach-loop after the first element is found?
This nantcontrib function will put the matching filenames into a delimited string..
If you know that only one matching file will exist then it may get you what you want. If there are several then you could use the nant substring function to just get the first match by taking the substring up to the first delimiter.
The following nant script:
<?xml version="1.0" encoding="utf-8"?>
<project default="find-file2">
<property name="NantContrib.dir" value="C:\Program Files\nantcontrib-0.85\" readonly="true" />
<target name="LoadNantContrib">
<loadtasks assembly="${NantContrib.dir}bin\NAnt.Contrib.Tasks.dll" />
</target>
<target name="find-file2" depends="LoadNantContrib">
<fileset id="find.set">
<include name="${param.dir}\**\${param.pattern}" />
</fileset>
<property name="return.file" value="${fileset::to-string('find.set', ' | ')}" />
<echo message="return.file=${return.file}"/>
<echo message="Found ${fileset::get-file-count('find.set')} files"/>
</target>
</project>
...and the following folder structure:
\---folderroot
+---folder1
| dontfindme.txt
| findme.txt
|
+---folder2
| dontfindme.txt
|
\---folderempty
...works as expected. Searching for findme.txt finds one file. Searching for dontfindme.txt finds two files. Searching for *.txt finds three files.
Example call:
nant -D:param.dir=folderroot -D:param.pattern=findme.txt
Example output:
find-file2:
[echo] return.file=C:\Documents and Settings\rbaker\My Documents\nantfindfile\folderroot\folder1\findme.txt
[echo] Found 1 files
BUILD SUCCEEDED