Inspect stdout from the middle of chained apps - stdout

Consider this example chain:
cat foo.txt | grep -v foo | grep -v bar | grep -v baz
I'd like to inspect the contents stdout of the second grep as well as the resulting stdout:
cat foo.txt | grep -v foo | grep -v bar | UNKNOWN | grep -v baz
So I need a tool, UNKNOWN, that for instance dumps the contents of stdout to a file and also passes stdout along the chain.
Does the tool, UNKNOWN, exists (both Windows and Linux answers are relevant) ?

I think there's a thing call 'tee' that gives you that.
Update reflecting comment from Bob:
cat foo.txt | grep -v foo | grep -v bar | tee -a inspection.txt | grep -v baz

Unable to give it a shot, but like Gabriel and Bob pointed out, the command $ tee (man tee) will help you out. The tee command will take input and echo it to stdout, as well as files. As Bob said in his comment:
cat foo.txt | grep -v foo | grep -v bar | tee -a inspection.txt | grep -v baz
Will take the output from grep -v bar and put it to stdout, as well as inspection.txt. The -a flag causes it to append to inspection rather than create a whole new file.

Related

Check docker instance in Bash

Having docker ps -a
I want to match the NAMES VERSION and STATUS.
docker ps -a --format "{{.Image}}\t{{.Status}}" | awk -F$"\t" '{printf "%s|%s\n", $1, $2}'
Output:
registry.com/project/glass/glass_front:2.2.15.4|Up 6 days
registry.com/project/glass/glass_proxy:2.2.15.4|Up 6 days
registry.com/project/glass/glass_modeles_front:2.1.5.2|Up 6 days
How can i modify my command to have this:
glass_front | 2.2.15.4 | Up 6 days
glass_proxy | 2.2.15.4 | Up 6 days
glass_modeles_front| 2.1.5.2 | Up 6 days
Try using colon as the separator in the docker ps command, then use sed to transform the colon to pipe and remove the prefix:
docker ps -a --format "{{.Image}}:{{.Status}}" \
| sed -e 's/:/ | /g' -e 's,^.*/,,'
Could you please try following, not tested it as don't have docker command. Its based on completely shown sample output of OP only.
docker ps -a --format "{{.Image}}\t{{.Status}}" \
| awk -F'\t' '{num=split($1,arr,"[/:]");print arr[num-1],arr[num],$2}'
OR(only using field separator capability of awk)
docker ps -a --format "{{.Image}}\t{{.Status}}" \
| awk -F"[/:\t]" '{print $4,$5,$NF}'
Explanation(1st solution): Running docker program(what OP shown) then passing its output as an input to awk command. In awk command setting field separator as TAB. Then splitting 1st field into an array(arr) with delimiter of /,:, then finally printing arr's 2nd last and last items here with 2nd field of current line.

grep: constructing a regex pattern to exclude several groups

I have a folder with three files:
$ ls
aaa.txt abc.txt def.txt
If I want to grep the output excluding the abc.txt file I can do:
$ ls | grep -v 'abc'
aaa.txt
def.txt
If I want to exclude two files I can do:
$ ls | grep -v 'abc' | grep -v 'def'
aaa.txt
But how can I do this using one regex and one grep invocation?
This does not work:
$ ls | grep -v '[(abc)(def)]'
neither does this:
$ ls | grep -v "abc|def"
Use the ERE(Extended Regular Expression) pattern for the alternation match | which is not enabled by default in BRE (which grep uses by default)
grep -vE "abc|def"
or use the extended grep, i.e. egrep which enables the ERE by default
egrep -v "abc|def"

Running `bash` using docker exec with xargs command

I've been trying to execute bash on running docker container which has specific name as follows. --(1)
docker ps | grep somename | awk '{print $1 " bash"}' | xargs -I'{}' docker exec -it '{}'
but it didn't work and it shows a message like
"docker exec" requires at least 2 argument(s)
when I tried using command as follows --(2)
docker ps | grep somename | awk '{print $1 " bash"}' | xargs docker exec -it
it shows another error messages like
the input device is not a TTY
But when I tried using $() (sub shell) then it can be accomplished but I cannot understand why it does not work with the two codes (1)(2) above (using xargs)
Could any body explain why those happen?
I really appreciate any help you can provide in advance =)
EDIT 1:
I know how to accomplish my goal in other way like
docker exec -it $(docker ps | grep perf | awk '{print $1 " bash"}' )
But I'm just curious about why those codes are not working =)
First question
"docker exec" requires at least 2 argument(s)
In last pipe command, standard input of xargs is, for example, 42a9903486f2 bash. And you used xargs with -I (replace string) option.
So, docker recognizes that 42a9903486f2 bash is a first argument, without 2nd argument.
Below example perhaps is the what you expected.
docker ps | grep somename | awk '{print $1 " bash"}' | xargs bash -c 'docker exec -it $0 $1'
Second question
the input device is not a TTY
xargs excutes command on new child process. So you need to reopen stdin to child process for interactive communication. (MacOS: -o option)
docker ps | grep somename | awk '{print $1 " bash"}' | xargs -o docker exec -it
This worked for me:
sudo docker ps -q | xargs -I'{}' docker exec -t {} du -hs /tmp/
The exec command you run is something like this:
docker exec -it 'a1b2c3d4 bash'
And that is only one argument, not two. You need to remove the quotes around the argument to docker exec.
... | xargs -I'{}' docker exec -it {}
Then you will exec properly with two arguments.
docker exec -it a1b2c3d4 bash
------ ---
first arg ^ ^ second arg

How to write noncapturing groups in egrep

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

Combining many greps in a single grep call

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/'

Resources