How to log xterm window from tcl script - linux

I am opening a xterm window from my tcl by exec xterm -geometry 78x36+0+0 -fn "-adobe-courier-medium-r-*-*-*-120-*-*-*-*-iso8859-1" -sl 10000 -sb -bg white -bd white -into..... I am executing other commands on this emulate terminal. Now i want to log output of those commands into a file from the same tcl script.
Can any one have idea about how to do it.... ?
Thanks in advance
murali krishna

Capturing from outside — from the perspective of the script doing exec xterm … -into … — is extremely hard, as there are no events you get when something draws on the subsidiary window (except in one case where you actually don't want them) and you'd end up just seeing a lot of bitmaps of what happened anyway; large and really uninformative. You need to use a different approach; you need to capture from the inside, to log the things that the user sees on the terminal. Fortunately, this isn't actually too hard to do.
To keep a complete log of what happens inside a terminal (where the terminal program itself doesn't offer the feature) your best bet is to run a little Expect script inside the terminal.
package require Expect
log_file /tmp/somefile.log
spawn $env(SHELL)
interact
exit
Run this inside the terminal (there's an option to xterm to do this) and it will record everything that happens inside. It's logged to a temporary file, /tmp/somefile.log, but you can change what name to use if you desire. It's probably a good idea to pass the log file in by an argument:
package require Expect
if {$argc < 1} {
error "not enough arguments"
}
# Unlike C, Tcl doesn't include interpreter name or script name in argv
log_file [lindex $argv 0]
spawn $env(SHELL)
interact
exit

Related

Launching a Python script in a separate console window...from a python script

I have a python command-line tool that allows the user to select a variety of options, each a module.
One of the options is a standalone python script that doesn't share any I/O or state with the main program, but it runs continuously and would be blocking. I'd really like to launch it in a separate console window, where the user will be prompted for input and it will run until they manually exit.
I've tried several subprocess options thus far, but the farthest I've gotten is launching a new window that just...hangs.
Of course, I'd like to be as OS-agnostic as possible. I'm guessing the type of terminal emulator matters here, though, among other things. Should I looking at the multiprocessing module?
I welcome any advice that would help me get on the right track or point out any obvious (or perhaps not-so-obvious) flaws in my perspective. I'd like to adhere to the best-practice for this situation but am just not experienced enough. Thanks.
Edit: I got this to work by calling the actual submodule:
os.system("gnome-terminal -e 'bash -c \"python3 -m name.of.module; exec bash\"'")
This works splendidly, but I get all this ugly output from Gnome inside of the main program that launched the second process:
# Option “-e” is deprecated and might be removed in a later version of gnome-terminal.
# Use “-- ” to terminate the options and put the command line to execute after it.
# _g_io_module_get_default: Found default implementation local (GLocalVfs) for ‘gio-vfs’
# posix_spawn avoided (fd close requested)
# _g_io_module_get_default: Found default implementation dconf (DConfSettingsBackend) for ‘gsettings-backend’
# watch_fast: "/org/gnome/terminal/legacy/" (establishing: 0, active: 0)
# unwatch_fast: "/org/gnome/terminal/legacy/" (active: 0, establishing: 1)
# watch_established: "/org/gnome/terminal/legacy/" (establishing: 0)
Using -- in lieu of -e causes a child process error. I've also tested other subprocess calls with the -- option and I still get some ugly output from Gnome. I can pipe stderr to /dev/null but I don't feel like this very clean.
Is this generally a sensible solution, or is this bad design (on my part, that is)?
Thus far, I've gotten this to work on both Linux and Mac. It's ugly, though; I'd welcome a better answer, but haven't found one.
def open_new_window(module_name):
if (operating_sys == "linux" or operating_sys == "linux2"):
os.system(f"gnome-terminal -e 2>/dev/null 'bash -c \"python3 -m app.{module_name}; exec bash\"'")
if (operating_sys == "darwin"):
os.system(f"""osascript -e 'tell app "Terminal"
do script "cd {root_path}; python3 -m app.{module_name}"
end tell' """)
else:
print("[-] Your operating system does not support this utility.\n")
It works. Passing stdout to /dev/null on the linux option will get rid of the messy Gnome output. This method allows me to dynamically call modules that need to run in their own console window, detached from the main program. For running scripts that don't need to share state, it works just fine and manages to be somewhat cross-platform.
Still, I feel like there must be a more Pythonic way to do this.
Note: I've noticed on many related posts, the statement "in a new window" causes some confusion. "In a new window" here means the app literally opens a new shell window (unfortunately, which shell will need to be hardcoded for you) and starts the module as a standalone process (the main app does not keep track of it). For others using this solution, keep this in mind - this is certainly NOT a good way to do this if you need to manage I/O from main instance.

How to use xdotool to open a new tab, switch to it and run commands in it

I am trying to write a bash script to automate running some commands. However some of these commands should be running in their own terminal tab.
So I use the following in my bash script to open a new tab:
xdotool key ctrl+shift+t
this does the job, but the next commands in my bash script are still executed in the previous terminal tab.
How can I make the new opened terminal tab active and run the next commands in this tab?
What Terminal Emulator are you using? It strongly depends on this.
In general, you could write the commands you want to execute in a shell script and tell your terminal emulator to execute the script once it has started.
Example with xterm:
echo '#!/bin/bash' > /tmp/thescript
echo 'ls -la' >> /tmp/thescript
chmod +x /tmp/thescript
xterm -hold -e /tmp/thescript
EDIT: I just saw that u asked for a way to achieve this with xdotool. So this answer might be invalid. Please tell me if so - then i'll delete it.
How are you using xdotool? It can be done with a chain, for example:
$ xdotool key "ctrl+shift+t"; xdotool type "ls"; xdotool key Return
If all you want is to run the commands in the background / in parallel, without synchronously waiting for each command to complete before the next begins, terminate them with an ampersand & to instruct the shell to do so.
Alternatively, you can execute the commands in their own subshells by surrounding each with parentheses ( ). If they are long running processes or you do not wish to pollute the original shell with their output, you can fork them off and capture their output to file with something like (setsid command 1>/path/to/log &).
If separate tabs is necessary requirement, you can use xdotool to key the switch-to-the-next-tab binding or similar, and then key the commands you must run in that tab.
Instead of sorting out that mess yourself, you could use a script from this answer by Jacob Vlijm, which wraps a windowed approach that uses xdotool and wmctrl to 'send' commands to different terminal windows. The script is written in python 3 but it can easily be rewritten for a shell environment of choice.
A more direct approach involves use of a TIOCSTI ioctl to inject characters into another terminal. According to the tty_ioctl manual page:
NAME
ioctl_tty - ioctls for terminals and serial lines
...
DESCRIPTION
The ioctl(2) call for terminals and serial ports accepts many possible
command arguments.
...
Faking input
TIOCSTI const char *argp
Insert the given byte in the input queue
...
Here are c and perl wrappers, and an example in python as referenced by this answer.

gnome-terminal executes commands from file

I need an example of gnome-terminal command to read lines of text from a file and executes them one by one in different terminal or a tab.
So this would be the process. I would run gnome terminal command and it would read 10 commands from a file. Then it would execute those 10 commands in 10 different tabs/terminals. And of course those tabs/terminals would remain opened. I found this question Avoid gnome-terminal close after script execution?
The third answer from the top is very helpful. I managed to open 1 command from a file. But I need 1 file with 10 command lines to be opened like I wrote above.
Thanks.
I recommend to use screen for this, if that can be acceptable to you.
You could create a commands.screenrc file like this:
screen bash -c 'command1; echo press any key; read'
screen bash -c 'command2; bash'
screen mutt
screen emacs
screen
You can define as many programs as you want. Start screen with:
screen -c commands.screenrc
I don't know what kind of commands you want to run. If you want to see their output, then write like the first example above: execute the command in a bash shell, which will "pause" after the command was executed. Or the second line, which, after running the command will start another bash shell. Otherwise the screen window would exit automatically.
If you are not familiar with screen, you will need to learn some basic key strokes to get around, and to be able to switch between windows. The first few pages of this presentation should be enough to get you started.

execute a gui application from the command line and send it to the background

Is there a command line utility that I can use for executing X based applications that will detach my applications from the terminal so they aren't closed if the terminal is closed?
I guess such a app could be called something like gnome-run if it existed.
I have tried dtach, but it seems that you have to provide a socket file which is a bit clunky to type. I have also tried nohup, but found that also to be a bit clunky to type by the time std out and err are redirected to /dev/null.
I guess I'm looking for a simple program that will do something similar to this:
#!/bin/bash
nohup $1 > /dev/null 2>&1 &
Yes, there is a way to do it: first you need to run your GUI app and send it to background, then you (probably) want to detach it from Bash task management. For example if I wanted to run gedit this way:
gedit &
disown %1
After that you can close your terminal window and gedit will not be killed. Enjoy!
You already wrote your program, it is called a shell script and you give it the name you like and put it somewhere. Then you either add that directory to your $PATH or in your bashrc you set:
alias gnome-run=<path>/my-awesome-script.sh
Why waste earth's resources on a program?
If you want to run an application (say, gedit) as if it was run from the GUI, use:
xdg-open /usr/share/applications/gedit.desktop
See this answer on superuser.

TCL - open a new terminal, do some operations in the opened terminal and close it

How can I open a new terminal from TCL code, do some operations (e.g. ls -l), get the results of those operations and close that terminal?
Does the exec command open a new terminal and all the operations are invoked in the terminal or when I call for example "cd .." with exec, that command has nothing to do with the linux terminal and linux commands, those are just pure tcl commands that have the same name as linux standard commands?
Sounds like you want Expect.
Any command you pass to exec will be sent to the system to be executed. exec does not open a terminal window to do this: it does not need to open a GUI window like a terminal just to interact with the underlying system.
A couple of specific notes about your example commands:
parsing the output of ls or ls -l is not recommended. Suppose you have an odd but valid filename like "foo\nbar". You're better off iterating over the results of Tcl's glob command.
cd happens to be a Tcl command.
I have done my task with this:
set cvsUpdStr [exec $pathToCvsInYourSystem -qn upd]
It does not open a terminal, but it does the task:
executes a command
results is being stored in cvsUpdStr and can be used later
Also it is possible to use it with catch to understand if it was executed correctly or to avoid errors:
if {[catch {exec $pathToCvsInYourSystem -qn upd} result]} {puts $result}

Resources