How to extract only first occurrence of a match between two patterns - regex

This is followup, but slightly different problem to another question that I posted earlier at:
How to extract everything between two patterns (using sed?)?
During testing, I have also found that in some cases, more than one of the records are not only in a single file, but also all the records are just together in a single line, with no newlines between them, and when I run the sed command on that one combined line, it seems like it will find a match, but the match, but it is not the first match (I don't actually know why it is matching the one that it is finding).
I know that the first "line" is also the most recent record, so I would like to perform a sed type match to extract the time from the first record, but only from the first record.
Here a snippet to illustrate what I tried to describe above:
UPDATE SUCCESS (key/name): 7c061313-9cbd-4bd1-8613-139cbd2bd1da/snctest38
UPDATE SUCCESS (key/name): 7ebab268-05dc-4110-bab2-6805dc2110f6/snctest4
UPDATE SUCCESS (key/name): 8ef15385-3d23-40e9-b153-853d2310e9fd/snctest5
UPDATE SUCCESS (key/name): 978bf8b5-b4aa-4cd4-8bf8-b5b4aaacd4b6/snctest6
UPDATE SUCCESS (key/name): 34f28da7-1311-4cb7-b28d-a713116cb77d/snctest7
UPDATE SUCCESS (key/name): 7be77991-4c73-4c35-a779-914c73ec359a/snctest8
</message><refDesc>PUSH Task 0a64cff0-b826-420b-a4cf-f0b826420bae 2_ldapadd</refDesc><refKey>0a64cff0-b826-420b-a4cf-f0b826420bae</refKey><status>SUCCESS</status></syncope21:exec><syncope21:exec xmlns:syncope21="http://syncope.apache.org/2.1"><end>2020-01-22T05:36:59.649Z</end><start>2020-01-22T05:36:59.639Z</start><jobType>TASK</jobType><key>c4a0f6fa-109e-4a25-a0f6-fa109e5a2505</key><refDesc>PROPAGATION Task 3a2457ef-556b-4f39-a457-ef556b6f3921 d228de62-2918-46fe-960a-a193c3bfa0c3</refDesc><refKey>3a2457ef-556b-4f39-a457-ef556b6f3921</refKey><status>SUCCESS</status></syncope21:exec><syncope21:exec xmlns:syncope21="http://syncope.apache.org/2.1"><end>2020-01-22T05:36:59.567Z</end><start>2020-01-22T05:36:59.558Z</start><jobType>TASK</jobType><key>e9defd1b-966f-4830-9efd-1b966f183008</key><refDesc>PROPAGATION Task a47fee5a-fea3-4422-bfee-5afea3e422c5 e7394424-a4b7-41fe-90a1-46e3b309e6f2</refDesc><refKey>a47fee5a-fea3-4422-bfee-5afea3e422c5</refKey><status>SUCCESS</status></syncope21:exec><syncope21:exec xmlns:syncope21="http://syncope.apache.org/2.1"><end>2020-01-22T05:36:59.485Z</end><start>2020-01-22T05:36:59.476Z</start><jobType>TASK</jobType><key>52ab4c49-e28d-49d3-ab4c-49e28d39d38e</key><refDesc>PROPAGATION Task 437e3eb4-487f-471c-be3e-b4487f971cdf 11f95ec1-ac16-4344-8741-ae362ec4b357</refDesc><refKey>437e3eb4-487f-471c-be3e-b4487f971cdf</refKey><status>SUCCESS</status></syncope21:exec><syncope21:exec xmlns:syncope21="http://syncope.apache.org/2.1"><end>2020-01-22T05:36:59.394Z</end><start>2020-01-22T05:36:59.385Z</start><jobType>TASK</jobType><key>17c947c9-eb8d-4222-8947-c9eb8d622288</key><refDesc>PROPAGATION Task 67956b5a-86a2-4f0c-956b-5a86a24f0c35 d7df1a03-a7f7-4a7b-8cab-d098852de2f3</refDesc><refKey>67956b5a-86a2-4f0c-956b-5a86a24f0c35</refKey><status>SUCCESS</status></syncope21:exec><syncope21:exec xmlns:syncope21="http://syncope.apache.org/2.1"><end>2020-01-22T05:36:59.312Z</end><start>2020-01-22T05:36:59.302Z</start><jobType>TASK</jobType><key>42a7e05a-5ed2-438c-a7e0-5a5ed2e38c64</key><refDesc>PROPAGATION Task d3d6026d-f4fd-4c64-9602-6df4fd1c6455 321861ed-3ede-4981-a6cc-cc193662a652</refDesc><refKey>d3d6026d-f4fd-4c64-9602-6df4fd1c6455</refKey><status>SUCCESS</status></syncope21:exec><syncope21:exec xmlns:syncope21="http://syncope.apache.org/2.1"><end>2020-01-22T05:36:59.226Z</end><start>2020-01-22T05:36:59.216Z</start><jobType>TASK</jobType><key>09e1767b-e243-47ea-a176-7be243a7eabd</key><refDesc>PROPAGATION Task 3dd00b2e-e0ab-43c8-900b-2ee0ab43c8de a3b19123-38de-4702-907a-11d7a14d7a64</refDesc><refKey>3dd00b2e-e0ab-43c8-900b-2ee0ab43c8de</refKey><status>SUCCESS</status></syncope21:exec><syncope21:exec xmlns:syncope21="http://syncope.apache.org/2.1"><end>2020-01-22T05:36:59.145Z</end><start>2020-01-22T05:36:59.135Z</start><jobType>TASK</jobType><key>b13e32e2-e361-4175-be32-e2e361917501</key><refDesc>PROPAGATION Task de139a01-fb49-4ea5-939a-01fb49cea584 2a6b616b-5319-423c-9d4a-47157dfe2cbc</refDesc><refKey>de139a01-fb49-4ea5-939a-01fb49cea584</refKey><status>SUCCESS</status></syncope21:exec><syncope21:exec xmlns:syncope21="http://syncope.apache.org/2.1"><end>2020-01-22T05:36:59.064Z</end><start>2020-01-22T05:36:59.054Z</start><jobType>TASK</jobType><key>cb24ebcd-6448-444b-a4eb-cd6448944bbc</key><refDesc>PROPAGATION Task aa947230-0cb2-40d2-9472-300cb270d230 0fade8e2-cfdf-4dc4-87ba-6d1352d32840</refDesc><refKey>aa947230-0cb2-40d2-9472-300cb270d230</refKey><status>SUCCESS</status></syncope21:exec><syncope21:exec xmlns:syncope21="http://syncope.apache.org/2.1"><end>2020-01-22T05:36:58.983Z</end><start>2020-01-22T05:36:58.973Z</start><jobType>TASK</jobType><key>04897743-9db6-496f-8977-439db6596fab</key><refDesc>PROPAGATION Task bc3ae42c-701e-4258-bae4-2c701e3258cc 98f9e4de-0e86-447d-9ffa-c87c96a947ca</refDesc><refKey>bc3ae42c-701e-4258-bae4-2c701e3258cc</refKey><status>SUCCESS</status></syncope21:exec><syncope21:exec xmlns:syncope21="http://syncope.apache.org/2.1"><end>2020-01-22T05:36:58.901Z</end><start>2020-01-22T05:36:58.891Z</start><jobType>TASK</jobType><key>999bab8f-9e64-4f53-9bab-8f9e64df5320</key><refDesc>PROPAGATION Task 15371c79-1ac0-4282-b71c-791ac0e28230 fbdf2574-5e7d-4e97-af94-e4d6169fc02b</refDesc><refKey>15371c79-1ac0-4282-b71c-791ac0e28230</refKey><status>SUCCESS</status></syncope21:exec><syncope21:exec xmlns:syncope21="http://syncope.apache.org/2.1"><end>2020-01-22T05:36:58.819Z</end><start>2020-01-22T05:36:58.810Z</start><jobType>TASK</jobType><key>81e907f6-d358-42b9-a907-f6d358e2b997</key><refDesc>PROPAGATION Task 5401a5d8-0407-4c2f-81a5-d804071c2fd0 81679e82-7006-4a2b-8914-f76fea587cec</refDesc><refKey>5401a5d8-0407-4c2f-81a5-d804071c2fd0</refKey><status>SUCCESS</status></syncope21:exec><syncope21:exec xmlns:syncope21="http://syncope.apache.org/2.1"><end>2020-01-22T05:36:58.738Z</end><start>2020-01-22T05:36:58.728Z</start><jobType>TASK</jobType><key>a6b42457-4b18-4dcc-b424-574b180dcc51</key><refDesc>PROPAGATION Task 90cc1ef6-5b5a-4f4d-8c1e-f65b5acf4d16 42ac4e4e-71e8-4cfb-8c2e-ceced4cdf029</refDesc><refKey>90cc1ef6-5b5a-4f4d-8c1e-f65b5acf4d16</refKey><status>SUCCESS</status></syncope21:exec><syncope21:exec xmlns:syncope21="http://syncope.apache.org/2.1"><end>2020-01-22T05:36:58.655Z</end><start>2020-01-22T05:36:58.645Z</start><jobType>TASK</jobType><key>8aba0dc9-3df4-4398-ba0d-c93df453989c</key><refDesc>PROPAGATION Task a074cbf2-de6c-4c15-b4cb-f2de6c4c15cd 6e37c044-5aa2-45e6-9626-27e0b2f52038</refDesc><refKey>a074cbf2-de6c-4c15-b4cb-f2de6c4c15cd</refKey><status>SUCCESS</status></syncope21:exec><syncope21:exec xmlns:syncope21="http://syncope.apache.org/2.1"><end>2020-01-22T05:36:58.571Z</end><start>2020-01-22T05:36:58.561Z</start><jobType>TASK</jobType><key>723f4400-49cd-4507-bf44-0049cdd507a1</key><refDesc>PROPAGATION Task cb87d842-2849-45ca-87d8-422849e5caa8 8bcd6de0-9e6f-4261-89b3-e3d56400f7af</refDesc><refKey>cb87d842-2849-45ca-87d8-422849e5caa8</refKey><status>SUCCESS</status></syncope21:exec><syncope21:exec xmlns:syncope21="http://syncope.apache.org/2.1"><end>2020-01-22T05:36:58.485Z</end><start>2020-01-22T05:36:58.474Z</start><jobType>TASK</jobType><key>a0b82ca0-8e2e-4b05-b82c-a08e2e8b0548</key><refDesc>PROPAGATION Task 828178dd-c1c8-4668-8178-ddc1c80668e7 d91141d7-2fd4-4fef-adc4-79cb81f1560b</refDesc><refKey>828178dd-c1c8-4668-8178-ddc1c80668e7</refKey><status>SUCCESS</status></syncope21:exec><syncope21:exec xmlns:syncope21="http://syncope.apache.org/2.1"><end>2020-01-22T05:36:58.401Z</end><start>2020-01-22T05:36:58.391Z</start><jobType>TASK</jobType><key>0c2f6210-f095-427c-af62-10f095927c09</key><refDesc>PROPAGATION Task 1b9cb7c6-7b51-4f4a-9cb7-c67b51bf4ae9 440fa8f9-ecd4-4053-9b07-fd22ed49b139</refDesc><refKey>1b9cb7c6-7b51-4f4a-9cb7-c67b51bf4ae9</refKey><status>SUCCESS</status></syncope21:exec><syncope21:exec xmlns:syncope21="http://syncope.apache.org/2.1"><end>2020-01-22T05:36:58.319Z</end><start>2020-01-22T05:36:58.309Z</start><jobType>TASK</jobType><key>77b14d6c-5be6-40e0-b14d-6c5be6f0e00b</key><refDesc>PROPAGATION Task 289a014d-3646-456d-9a01-4d3646356dd0 59fd7993-2737-46d6-8c0e-a26f8f02e234</refDesc><refKey>289a014d-3646-456d-9a01-4d3646356dd0</refKey><status>SUCCESS</status></syncope21:exec><syncope21:exec xmlns:syncope21="http://syncope.apache.org/2.1"><end>2020-01-22T05:36:58.237Z</end><start>2020-01-22T05:36:58.227Z</start><jobType>TASK</jobType><key>0f59fe8b-f057-4039-99fe-8bf057d0394e</key><refDesc>PROPAGATION Task 3f9f7751-787f-4dd2-9f77-51787fedd2bf 106abcb7-a5f0-4333-8e9e-0a81e84af904</refDesc><refKey>3f9f7751-787f-4dd2-9f77-51787fedd2bf</refKey><status>SUCCESS</status></syncope21:exec><syncope21:exec xmlns:syncope21="http://syncope.apache.org/2.1"><end>2020-01-22T05:36:58.154Z</end><start>2020-01-22T05:36:58.143Z</start><jobType>TASK</jobType><key>a5c44fb7-2b39-4e22-844f-b72b39de22ff</key><refDesc>PROPAGATION Task d9f712ea-d3a7-44a0-b712-ead3a784a05e efb1c4ca-6598-4cce-9aef-c749bf18e10b</refDesc><refKey>d9f712ea-d3a7-44a0-b712-ead3a784a05e</refKey><status>SUCCESS</status></syncope21:exec><syncope21:exec xmlns:syncope21="http://syncope.apache.org/2.1"><end>2020-01-22T05:36:58.066Z</end><start>2020-01-22T05:36:58.056Z</start><jobType>TASK</jobType><key>a9c2b65a-2cc6-4e70-82b6-5a2cc6fe7083</key><refDesc>PROPAGATION Task e504ad04-6afc-4880-84ad-046afcd8806c a025af4f-b7b8-4d90-917c-d3ff79d13780</refDesc><refKey>e504ad04-6afc-4880-84ad-046afcd8806c</refKey><status>SUCCESS</status></syncope21:exec><syncope21:exec xmlns:syncope21="http://syncope.apache.org/2.1"><end>2020-01-22T05:36:57.985Z</end><start>2020-01-22T05:36:57.975Z</start><jobType>TASK</jobType><key>a433e0da-71e5-4957-b3e0-da71e5d95744</key><refDesc>PROPAGATION Task 30597ec2-8cea-4744-997e-c28cea47446a 101d544c-5355-436b-9e93-aebcbf3b5da4</refDesc><refKey>30597ec2-8cea-4744-997e-c28cea47446a</refKey><status>SUCCESS</status></syncope21:exec><syncope21:exec xmlns:syncope21="http://syncope.apache.org/2.1"><end>2020-01-22T05:36:57.902Z</end><start>2020-01-22T05:36:57.891Z</start><jobType>TASK</jobType><key>a854c35a-291f-43c8-94c3-5a291fb3c891</key><refDesc>PROPAGATION Task 58ed721f-0b25-4a39-ad72-1f0b255a39c6 404aa838-b14a-40fd-8e6f-5a0522cfcce8</refDesc><refKey>58ed721f-0b25-4a39-ad72-1f0b255a39c6</refKey><status>SUCCESS</status></syncope21:exec><syncope21:exec xmlns:syncope21="http://syncope.apache.org/2.1"><end>2020-01-22T05:36:57.817Z</end><start>2020-01-22T05:36:57.807Z</start><jobType>TASK</jobType><key>19a4823a-b57e-4a51-a482-3ab57eaa5172</key><refDesc>PROPAGATION Task 9d0c6898-185b-4eac-8c68-98185b9eacb8 2b6dc9a1-8cf9-4b8c-a597-b1fc4ecd9b72</refDesc><refKey>9d0c6898-185b-4eac-8c68-98185b9eacb8</refKey><status>SUCCESS</status></syncope21:exec><syncope21:exec xmlns:syncope21="http://syncope.apache.org/2.1"><end>2020-01-22T05:36:57.728Z</end><start>2020-01-22T05:36:57.717Z</start><jobType>TASK</jobType><key>f5b0ccb5-304f-40d2-b0cc-b5304f30d21e</key><refDesc>PROPAGATION Task 98b26cc8-0ff9-487b-b26c-c80ff9487b59 ac164590-3e66-42a5-b7d7-c001fa641a24</refDesc><refKey>98b26cc8-0ff9-487b-b26c-c80ff9487b59</refKey><status>SUCCESS</status></syncope21:exec></syncope21:execs>
As you can see there are apparently multiple "lines" glommed together into one large line.
So how can some of the sed commands that were suggested in that previous thread be modified to match and extract just the first match?
Thanks,
Jim

If I'm reading your question right (and this is not easy given its dependence on other questions), you just want the shorted match between two given regexes (which are themselves just strings): <\/messages> and <\/start>.
sed '/<\/message>.*<\/start>/ { s:^.*</message>:</message>:; s:</start>.*$:</start>: }'
This uses POSIX sed since you have not specified that you're using GNU (e.g. via a Linux distribution). First, we check to ensure the line has a match. If it does, remove everything before the final </message> and then remove everything after the first </start>.
This would be more elegant with GNU (or BSD) sed since you can use backreferences to retain those tags:
sed -E '/<\/message>.*<\/start>/ { s:^.*(</message>):\1:; s:(</start>).*$:\1: }'
Personally, I'd use GNU grep (assuming it's compiled with libpcre to support -P):
grep -Po '</message>.*?</start>'
This will only display the matching text of the shortest match between those two given strings.

Related

TCL Regex Skipping Over a Set of Characters and Matching to a New line

I'm working with expect scripting in order to ssh into a device and pull information off of it. However, I'm facing issues parsing the expect_out(buffer) for the data from the commands I send.
This is the contents of my expect_out(buffer):
"mca-cli-op info\r\n\r\nModel: UAP-AC-Lite\r\nVersion: 6.0.21.13673\r\nMAC Address: 10:9f:5r:20:c5:7e\r\nIP Address: 123.123.1.123\r\nHostname: UAP-AC-Lite\r\nUptime: 152662 seconds\r\n\r\nStatus: Connected (http://base_controller<url;>/inform)\r\nUAP-AC-Lite-BZ.6.0.21# "
Right now I'm trying to get the Model (UAP-AC-LITE) without the Model tag.
So the regex expression I'm using is,
expect -re {(?=(Model: ))+[.*\$]}
set model "$expect_out(0,string)"
puts $model
The command doesn't work, but my thought process was that I would perform a look ahead for the Model tag, then match only the subsequent characters after it to the new line. I've tried replacing the "$" with \r\n but that doesn't work either. Can anyone explain what I'm doing wrong? Thanks for the help!
Note: If possible, I wouldn't want to include the newline either, as it might mess up commands that I run which use these variables.
You're close, but the regex is incorrect. Try
expect -re {Model:\s+([^\r]+)}
set model $expect_out(1,string)
The 1 in $expect_out(1,string) means the first set of capturing parentheses.
Regexes are documented at http://www.tcl-lang.org/man/tcl8.6/TclCmd/re_syntax.htm

sed - remove multiple lines if contains ends in 'can't find label'

I have a very large log file (more than 2GB) and would like to remove all debug logs if they contain 'EntityFramework'.
info: Microsoft.EntityFrameworkCore.Migrations[20405]
No migrations were applied. The database is already up to date.
dbug: Microsoft.EntityFrameworkCore.Infrastructure[10407]
'IDCDbContext' disposed.
warn: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[60]
Storing keys in a directory '/root/.aspnet/DataProtection-Keys' that may not be persisted outside of the container. Protected data will be unavailable when container is destroyed.
info: Hangfire.PostgreSql.PostgreSqlStorage[0]
Start installing Hangfire SQL objects...
Here I would like to remove the log below and keep the others
dbug: Microsoft.EntityFrameworkCore.Infrastructure[10407]
'IDCDbContext' disposed.
What I've tried so far:
sed -i '/^dbug/{:b,N;/^[[:lower:]]/!bb};/.*EntityFramework.*/d' logs
However it results in sed: can't find label for jump to b'
Any idea?
This job is better suited for awk:
awk '!p || !/^[[:blank:]]/ {p = /^dbug:/} !p' file
info: Microsoft.EntityFrameworkCore.Migrations[20405]
No migrations were applied. The database is already up to date.
warn: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[60]
Storing keys in a directory '/root/.aspnet/DataProtection-Keys' that may not be persisted outside of the container. Protected data will be unavailable when container is destroyed.
info: Hangfire.PostgreSql.PostgreSqlStorage[0]
Start installing Hangfire SQL objects...
We keep a flag p to control whether to print or not. p is set to 1 when a line starts with /dbug:/ and remains set for lines following dbug: that start with whitespaces.
The current error is due to the comma after the b label, there must be a semi-colon. Also, you should include /.*EntityFramework.*/d (or better, /EntityFramework/d) into the command block so that it is executed only inside it:
sed -i '/^dbug/{:b;N;/^[[:lower:]]/!bb;/EntityFramework/d}' logs
See the online demo.
1st solution: With your shown samples, please try following awk program, written and tested in GNU awk. Simple explanation would be, using awk's match function to match regex \ndbug:[^\n]*\n[^\n]* and printing only those lines which are required by OP's shown output(not matched lines only).
awk -v RS= 'match($0,/\ndbug:[^\n]*\n[^\n]*/){print substr($0,1,RSTART-1) substr($0,RSTART+RLENGTH)}' Input_file
2nd solution: Using record separator capability of awk and print the appropriate values needed by OP.
awk -v RS='\ndbug:[^\n]*\n[^\n]*\n' '{gsub(/\n+$/,"")}1' Input_file

Bash replace substring after first colon

I am trying to build a connection string that requires pulling 3 IP addresses from another config file. When I get those values, I need to replace the port on each. I plan to replace each port using simple Bash find and replace ${string/pattern/replacement} but my problem is I'm stuck on the best way to parse the pattern out of the IP.
Here is what I have so far:
myFile.config:
ip.1=ip-ip-1-address:1234:5678
ip.2=ip-ip-2-address:1234:5678
ip.3=ip-ip-3-address:1234:5678
Copying some other simple process, I found I can pull the value of each IP like this:
IP1=`grep "ip.1=" /path/to/conf/myFile.config | awk -F "=" '{print $2}'`
which gives me ip.1=ip-ip-1-address:1234:5678. However, I need to replace 1234:5678 with 6543 for example. I've been looking around and I found this awesome answer that detailed using Bash prefix substitution but that relies on knowing the parameter. for example, I would have to do it this way:
test=${ip1##ip-ip-1-address:}
which results in $test being 1234:5678. That's fine but maybe I don't know the IP address as the parameter, so I'm back to considering regex unless there's a way for me to use * as the parameter or something, but I have been unsuccessful so far. For regex, I have tried a bunch such as test=${ip1/(?<=:).*/}.
Note that ${ip1/(?<=:).*/} you tried is an example of string manipulation syntax that does not support regex, only specific patterns.
You seem to want
x='ip.1=ip-ip-1-address:1234:5678'
echo "${x%%:*}:6543" # => ip.1=ip-ip-1-address:6543
The ${x%%:*} takes the value of x and removes all chars from the end till the first : including it. :6543 is added to the result of this manipulation using "${x%%:*}:6543".
To extract that value, you may also use
awk '/^ip\.1=/{sub("^[^:]+:", "");print}' myFile.config
The awk command finds lines starting with ip.1= and then removes all text from the start till the first colon including the colon and only prints these values.

What regex can I use to match and replace full stops in multiple filenames?

I am looking to replace full stops in a filename however I need to remove some and replace others.
The file names are structured like so:
A.A M12345678 SOMEWORD 20.08.2019.pdf
A.A M12345678 SOMEWORD1 SOMEWORD2 20.08.2019.pdf
I want the format to be the following:
AA M12345678 SOMEWORD 20-08-2019.pdf
AA M12345678 SOMEWORD1 SOMEWORD2 20-08-2019.pdf
So the first full stop should be removed but the full stop encountered in the date should be a hyphen (-).
I have been using command prompt but I am running into some issues as I am fairly new to regular expressions.
I have tried approaching the problem one step at a time namely by just focusing on replacing the date format.
I've tested my regex using https://regexr.com/ and it matches correctly.
[0-9]\K[.]
My understanding of the code above should match the full stops in the date.
However when I run the following command:
ren *[0-9]\K[.].pdf -
It fails to find the file.
Expected Result
AA M12345678 SOMEWORD 20-08-2019.pdf
Actual Result
The expression I use just returns this error when I use the REN command.
"The filename, directory name, or volume label syntax is incorrect."
Pretty sure you could do this in the command-line with sed as follows. Run the following command:
sed -i "s/(\d\d)\.(\d\d)\.(\d\d\d\d)/\1-\2-\3 ; s/^(.)\.(.*)/\1\2/" <YOUR_FILE>
The -i flag is for modification in place. Here, I'm running two separate search-and-replace functions on each line; the first is to match to a date, and then format it accordingly, and the second is to match your A.A metadata and format it accordigly.
More about capture groups here.

Delete all lines upto some regex match

I want to delete everything from start of the document upto some regex match, such as _tmm. I wrote the following custom command:
command! FilterTmm exe 'g/^_tmm\\>/,/^$/mo$' | norm /_tmm<CR> | :0,-1 d
This doesn't work as expected. But when I execute these commands directly using the command line, they work.
Do you have any alternative suggestions to accomplish this job using custom commands?
It seems that you want to remove from beginning to the line above the matched line.
/pattern could have offset option. like /pattern/{offset}, :h / for detail, for your needs, you could do (no matter where your cursor is):
ggd/_tmm/-1<cr>
EDIT
I read your question twice, it seems that you want to do it in a single command line.
Your script has problem, normal doesn't support |, that is, it must be the last command.
try this line, if it works for you:
exe 'norm gg'|/_tmm/-1|0,.d