why does cat command keep io channel open? - io

so i started Narnia series in OverTheWire, and I'm having confusion on the first level.
So I figured out how to change the value to deadbeef, my problem came when I couldn't keep the IO channel open. So I did a little research and found out that you need to use cat command to keep the channel open.
My question is: why does cat command keep the channel ope?

Related

How to access mplayer output/know when mplayer video stopped playing?

I'm running a bash script that will play a video with mplayer depending on an input from an Arduino (on/off).
When the movie ends, I need to get a timestamp in a txt file. First question is whether there's a command in mplayer slave mode to tell me that, so I can output a timestamp easily.
If not, here's my strategy so far:
I'm running mplayer in slave mode with a fifo, where I echo "pause", whenever I want it to stop.
So, I've been doing this: echo "get_time_pos" to my fifo, which will tell mplayer to show in my Terminal the current position in the movie in seconds. When I say in my Terminal, it's in the same window where I'm running my script.
Now, I need to store this value in a variable to be able to compare with the total length and then output time.
I'm stuck at getting this output into a variable in my bash script.
I recently put together a small bash library that may grow with time. At the moment, it has the functionality you're looking for. I'll explain how to get the info you seek and then point you to my library which simplifies the task.
To get the information you seek, you don't even need to call get_time_pos. You can simply dump the mplayer (not running in quiet mode) output to a file and search that for the last timestamp. The trick here is that the timestamps listed in the dump may not be intuitive to search because of some special characters that control how text is displayed. You have to replace some of these special characters with new lines so that you can easily search it. Then you have to grab the last two lines in case the last line is not a timestamp.
Using my bash library:
Now, if you would like to simplify this process, check out this little library I wrote. Follow the usage directions on my GitHub to incorporate it, and then when you play a media file, play it with the playMediaFile function. If you do this, you'll be able to call the getElapsedSeconds or getElapsedTimestamp function to retrieve the current playback position or the playback position after mplayer has stopped. Storing it to a variable from within bash would be as simple as:
pos=$(getElapsedSeconds)
or
pos=$(getElapsedTimestamp)
This library contains other functions as well. The isFinishedPlaying function may or may not also be of use to you.

Interactive quiz in Bash (Multiple Q's)

I'm teaching an introductory Linux course and have abandoned the paper-based multiple-choice quizzes and have created interactive quizzes in Bash. My quiz script is functional, but kind of quick-and-dirty, and now I'm in the improvement phase and looking for suggestions.
First off, I'm not looking to automate the grading, which certainly simplifies things.
Currently, I have a different script file for each quiz, and the questions are hard-coded. That's obviously terrible, so I created a .txt file holding the questions, delimited by lines with "question 01" etc. I can loop through and use sed -n "/^quest.*$i\$/,/^quest.*$(($i+1))\$/p", but this prints the delimiter lines. I can pipe through sed "/^q/d" or head -n-1|tail -n+2 to get rid of them, but is there a better way?
Second issue: For questions where the answer is an actual command, I'm printing a [user]$ prompt, but for short-answer, I'm using a >. In my text file, for each question, the last line is the prompt to use. Initially, I was thinking I could store the question in a variable and |tail -1 it to get the prompt, but duh, when you store it it strips newlines. I want the cursor to immediately follow the prompt, so I either need to pass it to read -p or strip the final newline from the output. (Or create some marker in the file to differentiate between the $ and > prompt.) One thought I had was to store each question in a separate file and just cat it to display it, making sure there was no newline at the end. That might be kind of a pain to maintain, but it would solve both problems. Thoughts?
Now to how I'm actually running the quiz. This is a Fedora 20 box, and I tried copying bash and setuid-ing it to me so that it would be able to read the quiz script that the students couldn't normally read, but I couldn't get that to work. After some trial and error, I ended up copying touch and setuid-ing it to me, then using that to create their answer file in a "submit" directory with an ACL so new files have o=w so they can write to their answer file (in the quiz with >> echo) but not read it back or access the directory. The only major loophole I see with this is that they can delete their file by name and start the quiz over with no record of having done so. Since I'm not doing any automatic grading, I'm not terribly concerned with the students being able to read the script file, although if I'm storing the questions separately, I suppose I could make a copy of cat and setuid it to read in files that they can't access.
Also, I realize that Bash is not the best choice for this, and learning the required simple input/output for Python or something better would not take much effort. Perhaps that's my next step.
1) You could use
sed -n "/^quest.*$i\$/,/^quest.*$(($i+1))\$/ { //!p }"
Here // repeats the last attempted pattern, which is the opening pattern in the first line of the range and the closing pattern for the rest.
...by the way, if you really want to do this with sed, you better be damn sure that i is a number, or you'll run into code injection problems.
2) You can store multiline command output in a variable without problems. You just have to make sure you quote the variable everafter to avoid shell expansion on it. For example,
QUESTION=$(sed -n "/^quest.*$i\$/,/^quest.*$(($i+1))\$/ { //!p }" questions.txt)
echo -n "$QUESTION" # <-- the double quotes are important here.
The -n option to echo tells echo to not append a newline at the end, which should take care of your prompt problem.
3) Yes, well, hackery breeds more hackery. If you want to lock this down, the first order of business would be to not give students a shell on the test machine. You could put your script behind inetd and have the students fill it out with telnet or something, I suppose, but...really, why bash? If it were me, I'd knock something together with a web server and one of the several gazillion php web quiz frameworks. Although I also have to wonder why it's a problem if students can see the questions and the answers they gave. It's not like all students use the same account and can see each other's answers, is it? (is it?) Don't store an answer key on the same machine and you shouldn't have a problem.

How to open multiple instances of a program in Linux

Say for example, to open multiple instances of gedit editor I wrote a shell script like this-
gedit&
gedit&
gedit&
gedit&
But after I ran my shell script ./example.sh, I can find only one instance of gedit! I've even used the & operator, so that the shell doesn't wait for one instance to finish. Still I cannot see four instances of gedit.
Also I tried directly from the command prompt. If I just enter gedit& on the command line, it showed 1906 ( this is the PID of the newly created gedit process ), started one new gedit instance and returned to prompt again. When I typed gedit& on the command line, it showed 1909 this time, but no new instance of gedit! And I couldn't find any process with PID 1909 in the System Monitor too. Where did this new process go away?
Is the happening specific to gedit? If so, what is the generic behavior when creating multiple instances of a program?
It is specific to gedit. You are likely looking for gedit --new-window &.
From man gedit:
--new-window
Create a new toplevel window in an existing instance of gedit.
I came here, trying to start multiple instances of audacious.
Allowing only one instance is actually harder to implement, because the program needs to find and communicate with the instance already running. This is done via D-Bus. In order to prevent communication with the already started instance you can run the program in another D-Bus session:
nohup dbus-run-session audacious &
nohup dbus-run-session audacious &
Note: nohup will keep the program running even if the terminal is to be closed.
This method should also work for other programs which do not let the user choose between multiple instance vs. one instance.
Beware that this might introduce bugs, if multiple instances are accessing the same configuration files.
Tested with xfce 4.14.1 and dbus 1.12.20
For Scite:
scite -check.if.already.open=false &
A word of caution:
If you, like me, have your system running for multiple months and have edited some of your shortcuts or aliases to open with this hack, then after a while some programs will not start anymore because there are already too many open D-Bus session. In this case you have to kill the started D-Bus sessions, which do not close when the started program closes. The other way around, killing the D-Bus session, will also kill the opened program, so use with care! For me personally, I have some long running autostarted programs which I want to keep open (firefox), so I kill all but the first 10 D-Bus sessions with this:
for pid in $( ps --sort start_time -aux | grep dbus-daemon | tail +10 | awk '{ print $2; }' ); do kill $pid; done
The cleanest solution would be to write a launcher script which waits for the program to finish and then closes the opened D-Bus sessions. But this is a bit more difficult than it seems because it is hard to find the PID of the corresponding D-Bus session.
P.S.: I also used this hack because there seems to be some program on my system which, after a while, slows down the system's default file open dialog to take multiple minutes if not longer to open! Programs then seem to hang when trying to save or open files. A new D-Bus sessions seems to fix this for some reason. While writing this, I found that pkill gvfsd-trash also works and that it may have been this bug. So until this gets shipped, I guess I'll add pkill gvfsd-trash to my crontab.
This seems specific to gedit, perhaps there's some option to turn off the check for a running instance.
Looks like gedit is first looking for a running instance and simply ignores further start-requests (just a wild guess). But the manual page says, that you can open another window:
--new-window
Create a new toplevel window in an existing instance of gedit.
That wouldn't exactly solve your problem, but maybe that's what you were looking for in the first place.
Good luck,
Alex.
Using this in a script. I've found that it does what I need it to:
#!/bin/bash
xterm -e "gedit; bash" &disown

Linux Terminal: how to capture or watch other terminal session

Let say, I access to a server using ssh. In the same time, there is another person accessing that server.
Is it possible to watch what is going on in that person's terminal. Meaning, Can I just watch what he is typing?
If the other person is using the Linux console, you can use conspy.
If you mean that the other person wants you to see his console, you two can use screen to share a terminal. See http://www.gnu.org/software/screen/manual/html_node/Multiuser-Session.html for a full description of how to do it.
I also use an approach similar to what Maze said. This is a unidirectional sharing with read-only for the guest. This is how it works:
1) The host starts the script command writing somewhere where the guest has read access and set the permits as required, for example:
$ script -f /tmp/shared_screen
Script was started....
$ chmod 640 /tmp/shared_screen
$ chgrp shared_group /tmp/shared_screen
The -f flushes the contents permanently so you'll have a very low delay
2) The guest starts dumping the content of the file:
$ tail -f /tmp/shared_screen
In this case -f causes tail to wait on more output from the file. Use ctrl-C to stop displaying the file contents.
You can use the small tool script for logging the terminal into a file. The observing party can simply tail -f that file to follow.
This is a much simpler approach, but it works very nicely for most cases
To capture what Alice types in a terminal,
and then the next day let Bob see what was typed --
without any risk of Bob accidentally typing anything into that terminal --
Alice can type "showterm" ( http://showterm.io ) in her terminal window to start the recording.
To share a terminal so Alice and Bob both see "the same" terminal window and can both type commands into that window,
there seems to be three popular methods:
Byobu, tmux, or screen.
(tmate is a fork of tmux that works just as well, perhaps better).
"How to Share a Terminal Session with Friends" (with Byobu)
"Sharing Terminal Sessions With Tmux And Screen"
"ask Ubuntu: Share SSH Session at login"
"Remotely Working Together on a Terminal Session in Linux" (with screen)
Ubuntu: "HOWTO: Connect to another user's console terminal using 'screen'"
"HowTo Share A Terminal Session Using Screen"
Something nice and easy:
watch -n 1 cat /dev/vcsa1
watch -n 1 refers for the time to refresh.
You can also try "cat /dev/vcsa1"
Well depending on whether its for 'live' or 'ondemand' purposes, you could replay it online with a service like www.playterm.org.
If you want to share a session on a machine behind a firewall or NAT, you can use the open-source terminal sharing program Termbeamer.

What does the command "cat /tmp/dir/:0" do?

When I did the command above, X11 opened. I am perplexed. Did I run it? How can I be sure that I do not run any program when looking at things? I really hate the idea that reading a text file may execute a program. How is it programmable possible to make programs that executes when running a simple cat-command, or similar command?
If you run
file /tmp/:0
you should see that this is not a normal 'text' file but a socket. Aliasing ls thus
ls -F
will help identify such files automatically in your shell.
This sounds like OSX 10.5 behaviour.
launchd listens on a socket '/tmp/launch-xxxxxx/:0'. The DISPLAY variable is set to tell X applications to write to that socket. When an X application opens the socket, launchd automatically starts 'X11.app' to provide the application with a display.
cat'ing the socket opens it and triggers X11.app. I don't think there are any other instances of that behaviour configured by default.
machine:0 is an X display (the first display on 'machine')
I have never seen /tmp/:0 but it might be that your machine is configured so that all unmatched machine names map onto localhost.
You haven't executed anything, the X server will simply try and interpret any commands sent by cat as X instructions. It's like doing cat to an http address
The :0 thing is a socket refering to the X server. Programs use this socket to communicate with the X server (for example to draw a window). Reading from this socket somehow caused the server to activate. The X server must have been already running before you did this command.

Resources