Hey,
I saw this post and it helped me a lot so I share my version that came from these idea:
get_next_pts_nums(task_num) = begin # queriing the next terminal session IDs.
pts_ls = read(`ls /dev/pts`, String)
pts_nums = parse.(Int,split(pts_ls, '\n')[1:end-2])
sort!(pts_nums)
pts_ids = Vector{Int}(undef,task_num)
x, i, j = 0, 1, 1
while i <= task_num
while j <=length(pts_nums) && x == pts_nums[j]
x+=1
j+=1
end
pts_ids[i] = x
x+=1
i+=1
end
pts_ids
end
run_cmd(cmds::Vector{Cmd}, io) = for cmd in cmds run_cmd(cmd, io) end
run_cmd(cmd::Cmd, io) = begin
run(`echo "+ $cmd"`, io, io, io)
run(cmd, io, io, io)
end
run_in_terminal(cmd, t_id) = begin
run(`gnome-terminal -- zsh`)
pts_file = open("/dev/pts/$t_id", "w")
run_cmd(cmd, pts_file)
end
For local run this is damn fast and clean:
macro aync_run(cmd)
esc(:(for (i,t_id) in enumerate(get_next_pts_nums(length($cmd)))
@async run_in_terminal($cmd[i], t_id)
end))
end
# user, ip, cust_cmd = "testuser", "127.0.0.1", """echo "I am on the machine" """
@aync_run [`tty`,[`echo "haha whut"`, `tty`, `echo "I am on the machine"`, `echo "hell"`]]
Very ugly first try to run on different servers…
fn(user,ip) = begin
term_pts = get_next_pts_nums(1)[1]
run(`gnome-terminal -- zsh`)
@async begin
term_io = open("/dev/pts/$term_pts","w")
auth= `ssh -t $user@$ip`
run(`$auth echo "hello cmd"`,term_io,term_io,term_io)
run(`$auth tty`,term_io,term_io,term_io)
run(`$auth echo helllo`,term_io,term_io,term_io)
end
end
fn("testuser", "127.0.0.1")
I felt it would be too much time to parse the function with the macro add the terminal start and append the appropriate pts file for the run commands. So it is up to you to make it more clean. Also couldn’t agree on the best syntax, how do we want to use @async_run
in terms of function calls, so broadcast on the vector of inputs or not… and so on.
Don’t forget I used “zsh” so replace it to you bash.
Warning: We are calculating the “upcoming” terminal windows ID before it start, so there is a 0.000800 sec time till if someone else also start a windows from an external source, then there will be some fun overthere.
To cover the above mentioned issue, I tried to open my own pseudoterminal with the following commands but I didn’t know how to attach the next terminal on these file descriptors. I leave the efforst here, maybe someone will know how to finish.
pts_file = ccall((:open, "libc.so.6"), Cint, (Cstring, Cint), "/dev/ptmx",2)
ret2 = ccall((:grantpt, "libc.so.6"), Cint, (Cint,), pts_file)
ret3 = ccall((:unlockpt, "libc.so.6"), Cint, (Cint,), pts_file)
pts_file_url = ccall((:ptsname, "libc.so.6"), Ptr{UInt8} , (Cint,), pts_file)
@show unsafe_string(pts_file_url) # you can see the next terminal... but you already took the place... so... this isn't the next one already.
I hope these help someone who also wants multiple terminal windows in julia and send the appropriate commands to the approriate terminal window.