Run a program when new line appears in dmesg - linux

sudo dmesg -w|grep "Manufacturer: Keychron K1"| xargs -I{} xset r rate 250 70
It does not work, why?
I am trying to reset keyboard settings when the keyboard is reconnected, but I cannot get dmesg -w|xargs... combination to work. It supposed to be working, for example if I do this:
while :; do echo tick; sleep 1s; done|xargs -I{} date
I will get a new time printed every second. The idea was to use dmesg -w then grep then xargs but it does not work until xargs is killed from another terminal.
Why and how to fix?

You're asking an XY(Z) problem here, see "What is the XY problem?".
Your problem X is "how do I automatically have input devices configured in Xorg when hotplugged?"
And for that you simply want to write a xorg.conf.d InputClass rule that will make the appropriate settings for your keyboard:
https://www.x.org/releases/current/doc/man/man5/xorg.conf.5.xhtml#heading9
However you misidentified this problem as problem Y "how to automatically execute a program upon hotplug?" – for that we have UDev
For that problem look at UDev rules: https://wiki.archlinux.org/title/Udev
However misidentified problem Y as the "problem" Z "how can I execute the last part of a chain if pipe redirections, when a certain string appears". Tackling that does not solve your actual problem.
This
sudo dmesg -w | grep … | xargs …
pipes three programs together, which are all executing at the same time. xargs waits for the end of input and then executes whatever was passed to it as parameters. Of course dmesg -w will never produce an end-of-file.

Why
Buffering.
how to fix?
Set line buffering of tools with stdbuf or grep --line-buffered.

Related

How to grep and show only the data I want from the output of a running program?

I know by running
./mycommand | grep "keywords"
will get me the line of the keywords located after the program has finished executing.
But what if my program is running/looping constantly for a long time and logs out the results after each loop, how can I grep once a new output appears in the terminal without having the need to wait it finish executing?
In order to do this, the best is to log the results of mycommand to a logfile, something like /var/log/mycommand_logfile.log (your program mycommand might need to be modified in order to do so).
You then open a new terminal and launch the following command:
tail -f /var/log/mycommand_logfile.log | grep "keywords"
This will show the last lines, while they get written during mycommand's execution.
If I understand what you're saying, what you have should be doing what you want. Grep doesn't wait for its input to end. It processes it line by line and produces output whenever it encounters a line that matches what it's looking for.
If you're finding that it's not working this way, is there anything else in your command line that might be producing the blockage? Like, for example, if you're really doing something like:
./mycommand | sort | grep "keyword"
then the "sort" command will wait until it's gotten all the data so it can sort it before passing it on to grep.
Or perhaps the problem is that mycommand is a very resource-intensive operation, and running at a high priority, so that grep doesn't get any cpu cycles until mycommand isn't running any more. I'm just spitballing here. The point is, you're doing the command line right.

Redirect output from subshell and processing through pipe at the same time

tl;dr: need a way to process (with grep) an output inside subshell AND redirect all original output to the main stdout/stderr at the same time. I am looking for shell-independent (!) way.
In detail
There is a proprietary binary which I want to grep for some value
The proprietary binary from time to time might be interactive to ask for a password (depends on the internal logic)
I want to grep the output of the binary AND want being able to enter the password it that is required to proceed further
So the script which is supposed to achieve my task might look like:
#!/bin/sh
user_id=... # some calculated value
list_actions_cmd="./proprietary-binary --actions ${user_id}"
action_item=$(${list_actions_cmd} | grep '^Main:')
Here proprietary-binary might ask for a password through stdin. Since subshell inside $() catches the all output, an end-user won't understand that the list_actions_cmd waits for input. What I want is either to show all output of list_action_cmd AND grepping at the same time or at least caught the keyword that now user will be asked for a password and let him know about that.
Currently what I figured out is to tee the output and grep there:
#!/bin/sh
user_id=... # some calculated value
list_actions_cmd="./proprietary-binary --actions ${user_id}"
$list_actions_cmd 2>&1 | tee /tmp/.proprietary-binary.log
action_item=$(grep "^Main" /tmp/.proprietary-binary.log)
But I wonder is there any elegant shell-independent (not limited to bash which is quite powerful) solution without any intermediate temporary file? Thanks.
What about duplicating output to stderr if executed in a terminal:
item=$(your_command | tee /dev/stderr | grep 'regexp')

Use of tee command promptly even for one command

I am new to using tee command.
I am trying to run one of my program which takes long time to finish but it prints out information as it progresses. I am using 'tee' to save the output to a file as well as to see the output in the shell (bash).
But the problem is tee doesn't forward the output to shell until the end of my command.
Is there any way to do that ?
I am using Debian and bash.
This actually depends on the amount of output and the implementation of whatever command you are running. No program is obliged to print stuff straight to stdout or stderr and flush it all the time. So even though most C runtime implementation flush after a certain amount of data was written using one of the runtime routines, such as printf, this may not be true depending on the implementation.
It tee doesn't output it right away, it is likely only receiving the input at the very end of the run of your command. It might be helpful to mention which exact command it is.
The problem you are experienced is most probably related to buffering.
You may have a look at stdbuf command, which does the following:
stdbuf - Run COMMAND, with modified buffering operations for its standard streams.
If you were to post your usage I could give a better answer, but as it is
(for i in `seq 10`; do echo $i; sleep 1s; done) | tee ./tmp
Is proper usage of the tee command and seems to work. Replace the part before the pipe with your command and you should be good to go.

Read stdout from a process (linux embedded)

Before flagging the question as duplicate, please read my various issues I encountered.
A bit of background: we are developing a C++ application running on embedded ARM sbc using a lite variant of debian linux. The application start at boot launched by the boot script and print various information to stdout. What we would like is the ability to connect using SSH/Telnet and read the application output, without having to kill the process and restart it for the current bash session. I want to create a simple .sh script for non-tech-savvy people to use.
The first solution for the similar question posted here is to use gdb. First it's not user-friendly (need to write multiple commands manually) and I wonder why but it don't seems to output anything into the file.
The second solution strace -ewrite -p PID works perfectly, that's what I want. Problem is, there's a lot more information than just the stdout, and it's badly formatted.
I managed to get an "acceptable" result with strace -e write=1 -s 1024 -p 20049 2>&1 | grep "write(1," but it still have the superfluous write(1, "...", 19) = 19 text. Up to this point it's simply a bit of string formatting, and I've found on multiple other pages this line saying it achieve good formatting : strace -ff -e write=1,2 -s 1024 -p PID 2>&1 | grep "^ |" | cut -c11-60 | sed -e 's/ //g' | xxd -r -p
There are some things I find strange in this command (why -ff?, why grep "^ |"?, why use xxd there?) and it just don't output anything when I try it.
Unfortunately, we do use a old buggy version of busybox (1.7.1) that have some problem with multiple pipes. That bug gives me bad results. For example, if I only do grep it works, and if I only do cut it also works, but let's say "grep "write(1," | cut -c11-60" returns nothing.
I know the real solution would simply be to update busybox and use these multiple pipes to format the string, but we can't update it since the os distribution is already installed on thousands of boards shipped to our clients worldwide..
Anyone have a miraculous solution? Thanks
Screen can be connected to an existing process using reptyr (http://blog.nelhage.com/2011/01/reptyr-attach-a-running-process-to-a-new-terminal/), or you can use neercs (http://caca.zoy.org/wiki/neercs) which I haven't used but apparently is like screen but supports attaching to an existing process all by itself.

How can I make Bash automatically pipe the output of every command to something like tee?

I use some magic in $PROMPT_COMMAND to automatically save every command I run to a database:
PROMPT_COMMAND='save_command "$(history 1)"'
where save_command is a more complicated function. It would be nice to save also the head/tail of the output of each command, but I can't think of a reasonable way to do this, other than manually prepending some sort of shell function to everything I type (and this becomes even more painful with complicated pipelines or boolean expressions). Basically, I just want the first and last 10 lines of whatever went to /dev/tty to get saved to a variable (or even a file) - is there any way to do this?
script(1) will probably get you started. It won't let you just record the first and last 10 lines, but you can do some post-processing on its output.
bash | tee /dev/tty ./bashout
This saves all stdout gets saved to bashout.
bash | tee /dev/tty | tail > ./bashout
The tail of stdout of every command gets written to bashout.
bash | tee /dev/tty | sed -e :a -e '10p;$q;N;11,$D;ba' > ./bashout
The first and last 10 lines of stdout of every command gets written to bashout.
These don't save the command, but if you modify your save_command to print the command to stdout, it will get in there.

Resources