Piping To Grep Is Giving Too Many Results - linux

I'm trying to check whether a particular service is running via a Linux terminal, and the following command doesn't seem to be filtering the results as expected. Not sure what I'm doing wrong...
service --status-all | grep subversion
This produces several lines of output, including, for example,
[ ? ] Networking
I'm not sure why this is happening, since the string "subversion" is not contained within the above line...

You should use:
service --status-all |& grep subversion
Because the services without a status ([ ? ]) are sent to stderr, which is not pipelined to grep (and then it is printed on your terminal regardless).
|& sends stderr to stdout so grep is able to filter it.

Try this and redirect stderr (2) to stdout (1):
service --status-all 2>&1 | grep subversion

Related

Pass variables out of an interactive session from bash script

Hello People of the world,
I am trying to write a script that will allow user to failover apps between sites in bash.
Our applications are controlled by Pacemaker and I thought I would be able to write a function that would take in the necessary variables and act. Stop on one site, start on another. Once I have ssh'd to the remote machine, I am unable to get the value of the grep/awk command back for the status of the application in PCS.
I am encountering a few issues, and have tried answers from stackoverflow and other sites.
I send the ssh command to /dev/null 2>&1 as banners pop up on screen that unix admin have on the local user and -q does not deal with it - Does this stop anything being returned?
when using awk '{print \\\\\\$4}' in the code, I get a "backslash not last character on line" error
To get round this, I tried result=$(sudo pcs status | grep nds_$resource), however this resulted in a password error on sudo
I have tried >/dev/tty and >$(tty)
I tried to not suppress the ssh (remove /dev/null 2>&1) and put the output in variable at function call, removing the awk from the sudo pcs status entry.
result=$(pcs_call "$site1" "1" "2" "disable" "pmr")
echo $result | grep systemd
This was OK, but when I added | awk '{print \\\$4}' I then got the fourth word in the banner.
Any help would be appreciated as I have been going at this for a few days now.
I have been looking at this answer from Bruno, but unsure how to implement as I have multiple sudo commands.
Below is my strip down of the function code for testing on one machine;
site1=lon
site2=ire
function pcs_call()
{
site=$1
serverA=$2
serverB=$3
activity=$4
resource=$5
ssh -tt ${site}servername0${serverA} <<SSH > /dev/null 2>&1
sudo pcs resource ${activity} proc_${resource}
sleep 10
sudo pcs status | grep proc_$resource | awk '{print \\\$4}' | tee $output
exit
SSH
echo $output
}
echo ====================================================================================
echo Shutting Down PMR in $site1
pcs_call "$site1" "1" "2" "disable" "pmr"
I'd say start by pasting the whole thing into ShellCheck.net and fixing errors until there are no suggestions, but there are some serious issues here shellcheck is not going to be able to handle alone.
> /dev/null says "throw away into the bitbucket any data that is returned. 2>&1 says "Send any useful error reporting on stderr wherever stdout is going". Your initial statement, intended to retrieve information from a remote system, is immediately discarding it. Unless you just want something to occur on the remote system that you don't want to know more about locally, you're wasting your time with anything after that, because you've dumped whatever it had to say.
You only need one backslash in that awk statement to quote the dollar sign on $4.
Unless you have passwordless sudo on the remote system, this is not going to work out for you. I think we need more info on that before we discuss it any deeper.
As long as the ssh call is throwing everything to /dev/null, nothing inside the block of code being passed is going to give you any results on the calling system.
In your code you are using $output, but it looks as if you intend for tee to be setting it? That's not how that works. tee's argument is a filename into which it expects to write a copy of the data, which it also streams to stdout (tee as in a "T"-joint, in plumbing) but it does NOT assign variables.
(As an aside, you aren't even using serverB yet, but you can add that back in when you get past the current issues.)
At the end you echo $output, which is probably empty, so it's basically just echo which won't send anything but a newline, which would just be sent back to the origin server and dumped in /dev/null, so it's all kind of pointless....
Let's clean up
sudo pcs status | grep proc_$resource | awk '{print \\\$4}' | tee $output
and try it a little differently, yes?
First, I'm going to assume you have passwordless sudo, otherwise there's a whole other conversation to work that out.
Second, it's generally an antipattern to use both grep AND awk in a pipeline, as they are both basically regex engines at heart. Choose one. If you can make grep do what you want, it's pretty efficient. If not, awk is super flexible. Please read the documentation pages on the tools you are using when something isn't working. A quick search for "bash man grep" or "awk manual" will quickly give you great resources, and you're going to want them if you're trying to do things this complex.
So, let's look at a rework, making some assumptions...
function pcs_call() {
local site="$1" serverA="$2" activity="$3" resource="$4" # make local and quotes habits you only break on purpose
ssh -qt ${site}servername0${serverA} "
sudo pcs resource ${activity} proc_${resource}; sleep 10; sudo pcs status;
" 2>&1 | awk -v resource="$resource" '$0~"proc_"resource { print $4 }'
}
pcs_call "$site1" 1 disable pmr # should print the desired field
If you want to cath the data in a variable to use later -
var1="$( pcs_call "$site1" 1 disable pmr )"
addendum
Addressing your question - use $(seq 1 10) or just {1..10}.
ssh -qt chis03 '
for i in {1..10}; do sudo pcs resource disable ipa $i; done;
sleep 10; sudo pcs status;
' 2>&1 | awk -v resource=ipa '$0~"proc_"resource { print $2" "$4 }'
It's reporting the awk first, because order of elements in a pipeline is "undefined", but the stdout of the ssh is plugged into the stdin of the awk (and since it was duped to stdout, so is the stderr), so they are running asynchronously/simultaneously.
Yes, since these are using literals, single quotes is simpler and effectively "better". If abstracting with vars, it doesn't change much, but switch back to double quotes.
# assuming my vars (svr, verb, target) preset in the context
ssh -qt $svr "
for i in {1..10}; do sudo pcs resource $verb $target \$i; done;
sleep 10; sudo pcs status;
" 2>&1 | awk -v resource="$target" '$0~"proc_"resource { print $2" "$4 }'
Does that help?

How to forward dmesg live output through SSH on Linux

On VMWare or on bare metal, Linux display by default live dmesg content directly to stdout.
But when I'm connected through SSH, it doesn't show up even to the command succeeds
How do I forward every dmesg log through SSH ?
dmesg -wH, watch or tail are not what i'm looking for. I don't want to see the whole dmesg, only the live ones and without disrupting my shell.
Thanks #mjf, you were close.
dmesg -W & doesn't seems to be working since -W uppercase doesn't exist, but dmesg -w & with -w lowercase works perfectly.
To disable messages to console: echo 0 > /proc/sys/kernel/printk. To read messages at a remote machine: ssh yourname#frommachine "cat /dev/kmsg" and to get it into a file at the remote machine while watching: ssh yourname#frommachine "cat /dev/kmsg" | tee frommachinessyslog.log.

bash redirect output to file but result is incomplete

The question of redirecting output of a command was already asked many times, however I am having a strange behavior. I am using a bash shell (debian) with version
4.3.30(1)-release and tried to redirect output to a file, however not everything are logged in the file.
The bin file that I tries to run is sauce-connectv4.4.1 for linux (client of saucelabs that is publicly available in internet)
If I run
#sudo ./bin/sc --doctor
it showed me a complete lines
it prints :
INFO: resolved to '23.42.27.27'
INFO: resolving 'g2.symcb.com' using
DNS server '10.0.0.5'...
(followed by other line)
INFO: 'google.com' is not in hosts file
INFO: URL https://google.com can be reached
However, if I redirect the same command to a file with the following command
#sudo ./bin/sc --doctor > alloutput.txt 2>&1
and do
#cat alloutput.txt
the same command output is logged, but deprecated as following:
INFO: resolved to '23.42.2me#mymachine:/opt/$
It has incomplete line, and the next lines that follows are not even logged (missing).
I have tried with >> for appending, it has the same problem. Using command &> alloutput.txt also is not printing the whole stuff. Can anyone point out how to get all lines of the above command to be logged completely to the text file?
UPDATE
In the end I manage to use the native binary logging by using --log
alloutput.txt where it completely provide me with the correct output.
However I let this issue open as I am still wondering why one misses some information/lines by doing an output redirection
you should try this: stdbuf -o0
like:
stdbuf -o0 ./bin/sc --doctor 2>&1 | tee -a alloutput.txt
That is a funny problem, I've never seen that happening before. I am going to go out on a limb here and suggest this, see how it works:
sudo ./bin/sc --doctor 2>&1 | tee -a alloutput.txt
#commandtorun &> alloutput.txt
This command will redirects both the error and output to same file.

Best method to output log content to listening port

I am outputting content of a log via netcat to an application over the network. I don't know if what I'm doing is the most efficient, especially when I notice the netcat session becomes non-responsive. I have to stop netcat and start it again for the application to work again.
The command I run is:
/bin/tail -n1 -f /var/log/custom_output.log | /bin/nc -l -p 5020 --keep-open
This needs to run like this 24/7. Is this the most efficient way of doing it? How can I improve on it so I don't have to restart the process daily?
EDIT
So I realised that when the log is being rotated, netcat is locked onto a file that's not longer being written to. I can deal with this easily enough.
The question still stands. Is this the best way to do something like this?
It's been 6 years, but maybe someone will come in handy.
To account for log rotation, use tail with the -F flag.
nc (aka netcat) variant
LOG_FILE="/var/log/custom_output.log"
PORT=5020
tail -n0 -F "$LOG_FILE" | nc -k -l -p $PORT
Notes:
Flag -k in nc is analog to --keep-open in "the OpenBSD rewrite of netcat";
Multiple clients can connect to nc at the same time, but only the first one will be receive appended log lines;
tail will run immediately, so it will collect appended log lines even if no client is connected. Thus, the first client can receive some buffered data - all log lines that have been appended since tail was run.
socat variant
LOG_FILE="/var/log/custom_output.log"
PORT=5020
socat TCP-LISTEN:$PORT,fork,reuseaddr SYSTEM:"tail -n0 -F \"$LOG_FILE\" </dev/null"
Note: here socat will fork (clone itself) on each client connection and start a separate tail process. Thus:
Each connected client will receive appended log lines at the same time;
Clients will not receive any previously buffered by tail strings.
additional
You can redirect stderr to stdout in the tail process by adding 2>&1 (in both variants). In this case, clients will receive auxiliary message lines, e.g.:
tail: /var/log/custom_output.log: file truncated;
tail: '/var/log/custom_output.log' has become inaccessible: No such file or directory - printed when the log file has been removed or renamed, only if -F is used;
tail: '/var/log/custom_output.log' has appeared; following new file - printed when a new log file is created, only if -F is used.

How to redirect output of cu to a file ?

I am using cu utility to connect my Cubieboard 1 with my laptop. As I boot my Cubieboard , it sends the boot log to my terminal.
What I want is that the output should be displayed to my screen as well as be sent to some log file which I specify.
I can't find any option to do the same. Any ideas on how I could do that ?
Alternatively, if standard error should be in the file
<command> 2>&1 | tee log.txt
or
<command> |& log.txt
You could pipe into tee. You should then see output on screen and logged to a file of your choice.
<command> | tee log.txt

Resources