I want to grep a multiline pattern from tcpdump output like the following:
sudo tcpdump -A -s0 | grep -Pzo 'foo.*\n.*bar'
However, it does not seem to work. But it works if I dump the data into a file and then grep the file. How can I make the command using pipe working?
Try to add -l:
-l Make stdout line buffered. Useful if you want to see the data while capturing it.
E.g.,
tcpdump -l | tee dat
tcpdump -l > dat & tail -f dat
I still don't get why the grep does not work above even with -l option for tcpdump, but I found this stackoverflow post How to find patterns across multiple lines using grep?. So I tried pcregrep, and it worked.
sudo tcpdump -A -s0 | pcregrep -Mo "foo.*\n.*bar"
I was having problems piping the output to tail even with the -l switch as well. I was able to solve my problem by using multitail instead of tail -F.
This worked for me: multitail -l "tcpdump -li eth0"
Related
I would like to be able to do something similar to this is PowerShell
docker logs -f my-container | grep -q "string-to-match"
i.e. to follow a log file and when a string is matched you stop follow the file. My idea was to try something like this
docker logs -f my-container | Select-String "string-to-match".
I know it's not complete but I can't figure out how to make it work. I also did try to use WSL2 like this
docker logs -f my-container | wsl grep -q "string-to-match".
but it keeps following the log even after a match has been found!
A WSL-solution would solve my problem but a native PowerShell-solution would be preferable!
I tried with ugrep.exe in PowerShell:
docker logs -f my-container | ugrep -q "string-to-match"
and that appears to work fine as it stops at the first match. This can also be done with ugrep -m1 "string-to-match" to report the line that matched, since -m1 stops searching further after the first hit.
I have a fish shell completion like this for docker:
# 'docker-subcommands.txt' is an exhaustive list derived from the "Usage" message.
set -l subcoms (cat /etc/fish/completions/docker-subcommands.txt)
# Found '__fish_seen_subcommand_from' in the completion for `systemctl`
# (in /usr/share/fish/completions/...).
complete -f -c docker -n "not __fish_seen_subcommand_from $subcoms" -a "$subcoms"
function _docker_container_action
# The placeholder is needed here because fish will choke on an empty completion list.
echo (docker ps -aq) '{z-placeholder}'
end
function _docker_image_action
echo (docker images -q) '{z-placeholder}'
end
for sc in cp exec inspect restart rm start stop
complete -c docker -n "contains $sc (commandline -poc)" -x -a (_docker_container_action)
end
for sc in rmi run
complete -c docker -n "contains $sc (commandline -poc)" -x -a (_docker_image_action)
end
The problem is that the completion for image and container IDs needs to be dynamic (like file completion), whereas the above seems to run the -a command when the completion file is (re-)sourced.
How can I make this refresh the options when the completion is actually being applied?
I should mention that I've tried quoting the -a command, as seems to be common practice. But then instead of an option for each ID, I get only one completion option, a long string with space escapes in it (\) containing the IDs and \{z-placeholder} at the end. :(
[...] Quoting the -a command does work as long as its output is not produced by echo (which stringifies it). Turns out -a's "choking" problem is not having an argument, which is what happens if you put docker ps -aq there directly and there are no container IDs to list. So this pattern works:
function _docker_container_action
docker ps -aq
end
complete -c docker -n "contains $sc (commandline -poc)" -x -a "(_docker_container_action)"
And no need for my placeholder either.
whereas the above seems to run the -a command when the completion file is (re-sourced).
That's because you've included it here as a command substitution, so when the file is sourced, it expands, and the completion system has no idea what it was before.
But the -a option knows to expand its argument at completion-time, so all you need to do is quote it:
complete -c docker -n "contains $sc (commandline -poc)" -x -a "(_docker_container_action)"
docker ps sorts by time, but the most recent docker instance is at the very top. This means if you started very many instances you have to scroll all the way to the top to see them. How do we output "docker ps -a" in reverse order, so that the most recent instance is printed at the bottom?
You can pipe the output to tac[1] like:
docker ps -a | tac
[1] From man tac: tac - concatenate and print files in reverse
Latest created container:
docker ps -a -l
Latest 5 created containers:
docker ps -a -n 5
As far as I know ordering is not possible but maybe you don't really need it...
It's enough to get what you want.
$ docker ps -a --format "table {{.ID}}\t{{.Names}}\t{{.CreatedAt}}" | (read -r; printf "%s\n" "$REPLY"; sort -k 3 -r )
See also
How to sort or order results docker ps --format?
The following command does not correctly capture the 16714 from 16714 ssh -f -N -T -R3300:localhost:22
egrep -o '^[^ ]+(?= .*[R]3300:localhost:22)'
(However swapping to grep does if you use the -P flag. I was expecting egrep to be able to handle this)
grep -P forces grep to use the Perl regexp engine.
egrep is the same as grep -E and it forces grep to use the ERE (extended regular expression) engine, that does not support lookahead.
You can find a quick reference of the differences between Perl and ERE (and others) here : http://www.greenend.org.uk/rjk/tech/regexp.html
To handle this with POSIX grep, you would use grep to isolate the lines of interest and then use cut to isolate the fields of interest:
$ echo "16714 ssh -f -N -T -R3300:localhost:22" | grep 'R3300:localhost:22' | cut -d' ' -f1
16714
Or, just use awk:
$ echo "16714 ssh -f -N -T -R3300:localhost:22" | awk '/R3300:localhost:22/{print $1}'
16714
I've a script where I've to check if a process is running by its name and I'm doing it using ps and grep. The problem is that I've to grep many things to avoid to find false positive.
By now, I've a grep chain that looks as follow:
ps -ef | grep -i $process_name | grep -i perl | grep -v do_all | grep -v grep
Four greps. Three of them are there to avoid false positive.
I would like to know if there's a way to avoid such 'piping chain' and use a single grep to achieve the same result.
Though some of you could answer that there are cleaner way to find out if a process exists, I would like the same to have an answer to this question, just to better understand the usage of the grep command.
There's no real reason to avoid chaining them, is there?
If you really wanted to you could combine them with | in egrep:
ps -ef | egrep -i "$process_name|perl" | egrep -v 'do_all|grep'
Here's one way using GNU awk:
ps -ef | awk -v process="$process_name" 'BEGIN { IGNORECASE=1 } $0 ~ process && /perl/ && !/do_all/'