/ Today I learnt / notes

TIL: sed regex ranges

October 22, 2019

One can use sed and regular expressions to find chunks of text that span multiple line.

To look for ranges of lines in other words with sed:

sed '/range-start-line-regex/,/range-end-line-regex/ other commands' $file

Example

I'm a Java developer so the example will be from Java world. I was on a support case and we were trying to debug a problem a customer had. As part of the debugging process we've requested the customer to take a number of thread dumps.

The thread dumps we've received contain hundreds of threads. If you don't know, that's how a thread in a thread dump looks like:

"hz.hazelcast.cached.thread-15" #368 prio=5 os_prio=0 tid=0x00007f0634cbb800 nid=0x3fd1 waiting on condition [0x00007f05aa0dd000]
   java.lang.Thread.State: TIMED_WAITING (parking)
	at sun.misc.Unsafe.park(Native Method)
	- parking to wait for  <0x0000000640002c60> (a java.util.concurrent.SynchronousQueue$TransferStack)
	at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:215)
	at java.util.concurrent.SynchronousQueue$TransferStack.awaitFulfill(SynchronousQueue.java:460)
	at java.util.concurrent.SynchronousQueue$TransferStack.transfer(SynchronousQueue.java:362)
	at java.util.concurrent.SynchronousQueue.poll(SynchronousQueue.java:941)
	at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1073)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1134)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at java.lang.Thread.run(Thread.java:748)
	at com.hazelcast.util.executor.HazelcastManagedThread.executeRun(HazelcastManagedThread.java:76)
	at com.hazelcast.util.executor.HazelcastManagedThread.run(HazelcastManagedThread.java:92)

   Locked ownable synchronizers:
	- None

I was interested in threads that look like this:

"spring-startup" #65 daemon prio=5 os_prio=0 tid=0x00007f0706f68800 nid=0x624 runnable [0x00007f063911a000]
   java.lang.Thread.State: RUNNABLE
	at sun.nio.ch.FileDispatcherImpl.read0(Native Method)
	at sun.nio.ch.SocketDispatcher.read(SocketDispatcher.java:39)
	at sun.nio.ch.IOUtil.readIntoNativeBuffer(IOUtil.java:223)
	at sun.nio.ch.IOUtil.read(IOUtil.java:197)
	at sun.nio.ch.SocketChannelImpl.read(SocketChannelImpl.java:380)
	- locked <0x00000006d99b7140> (a java.lang.Object)
  ................................
  at java.lang.Thread.run(Thread.java:748)

In order to find those chunks of text in dozen of files with thousands lines of thread stacks I used sed:

for file in $(find .. -name "threads.*.txt"); do \
  sed -En '/^"spring-startup".*$/,/^[[:space:]]*$/ p' $file> $(basename $file);
done

Here I go through files and for each file I ask sed to find ranges of lines which start with line that matches ^"spring-startup".*$ and ends with line that matches ^[[:space:]]*$ and print them: p

As result I have bunch of files that contain only stack traces for spring-startup threads.