Issue opening new Mac Terminal with arguments to run Mongo shell [duplicate] - mongodb

Is there a way to pass arguments to a program being run via:
open -a /Applications/Utilities/Terminal.app ~/my_executable
I have tried:
open -a /Applications/Utilities/Terminal.app ~/my_executable arg1 arg2
But this is interpreted as telling the terminal to open ~/my_executable ~/arg1 ~/arg2.
I have tried:
open -a /Applications/Utilities/Terminal.app '~/my_executable arg1 arg2'
But it picks up arg1 and arg2 as if they were part of the path rather than arguments.
I have tried:
open -a /Applications/Utilities/Terminal.app ~/my_executable | xargs arg1 arg2
I have also tried:
open -a /Applications/Utilities/Terminal.app ~/my_executable --args arg1 arg2
But with that flag, args are passed to the terminal.
NOTE
I am only allowed to change the arguments to Terminal.app (the part within [ ]):
open -a /Applications/Utilities/Terminal.app [~/my_executable arg1 arg2]

Edit: Leaving the original answer below as some people seem to find it useful, but keep in mind that this doesn't really answers OP's question, this is to pass arguments to an app opened with "open" not to and app opened with Terminal.app which was opened with "open".
You can find your answer by running open without arguments:
% open Usage: open [-e] [-t] [-f] [-W] [-R] [-n] [-g] [-h] [-b <bundle identifier>] [-a <application>] [filenames] [--args arguments]
[...]
--args All remaining arguments are passed in argv to the application's main() function instead of opened.
[...]
You can see there is an option --args you can use it like this:
open ./Untitled.app --args arg1 arg2 arg3
I tested it on el Capitan (10.11.3) so I don't know if the option is present in earlier versions.

Probably the easiest way is to create a temporary shell script, e.g.
$ echo "~/my_executable arg1 arg2" > /tmp/tmp.sh ; chmod +x /tmp/tmp.sh ; open -a Terminal /tmp/tmp.sh ; rm /tmp/tmp.sh

Yes, I know. need to manage another script.
but think differently. you work not on Terminal, but on Script Editor.
(not bash scripting, but AppleScript'ing)
property testScript : "/tmp/sh.sh"
set input to display dialog "args?" default answer ""
log input
tell application "Terminal"
activate
do script testScript & " " & text returned of input
end tell

For those with having an issue with Paul R's answer, add the ; rm /tmp/tmp.sh to the tmp.sh script itself. Don't add a sleep command like Maksim as that creates a race condition.
echo "~/my_executable arg1 arg2 ; rm /tmp/tmp.sh" > /tmp/tmp.sh ; chmod +x /tmp/tmp.sh ; open -a Terminal /tmp/tmp.sh

Use the --args switch before your arguments.
open ./Terminal.app --args --your-args
From the docs:
--args: All remaining arguments are passed in argv to the application's main() function instead of opened.

Related

Can you get full command line from process ID (including command line arguments, etc)?

This question is in addition to the question asked here: https://unix.stackexchange.com/questions/163145/how-to-get-whole-command-line-from-a-process. On my system, the following command results in a PID (as expected):
CUDA_VISIBLE_DEVICES=4,5 python3 main.py 1> out.txt 2> err.txt &
Now, the methods in the stack exchange link above provide many solutions. However, when trying these solutions, I only receive the following information:
python3 main.py
Is there a way to return the entire command line "CUDA_VISIBLE_DEVICES=4,5 python3 main.py 1> out.txt 2> err.txt &", not just the portion "python3 main.py"?
No.
Assuming you're on a Linux system, you can find the individual bits, but you can't put it together.
Assume also that the process's PID is in $pid
The CUDA_VISIBLE_DEVICES=4,5 variable gets added to the environment of the python command. You can find it in /proc/$pid/environ but you can't tell which of those variables were specified on the command line: the user could have written
export CUDA_VISIBLE_DEVICES=4,5
python3 main.py 1> out.txt 2> err.txt &
The file redirections are available in /proc/$pid/fd:
/proc/$pid/fd/1 is a symbolic link to out.txt
/proc/$pid/fd/2 is a symbolic link to err.txt
I don't know how to tell if a process is running in the background.
Since you're just interested in the environment: with bash
declare -A environ
while IFS='=' read -r -d '' var value; do
environ["$var"]="$value"
done < /proc/$pid/environ
echo "process has CUDA_VISIBLE_DEVICE value ${environ[CUDA_VISIBLE_DEVICE]}"

How do i start an xterm and follow by setenv in the new xterm?

I am writing a perl script, and the objective is to kick start an xterm, follow by setenv, follow by invoke a tool that pre-installed in the system.
Here is my system call command in my perl script
system("xterm","-hold", "-e", "setenv ZI_LIBERTY_IGNORE_CONSTRUCT_FILES $RAW_RF_DIR/lib/lib2v/qcdc_ignore", "setenv HOME_0IN /p/hdk/rtl/cad/x86-64_linux26/mentor/questaCDC/V10.4g_5/linux_x86_64", "modpath -n 1 \$HOME_0IN/bin", "modpath -n 1 \$HOME_0IN/modeltech/bin", "/p/hdk/rtl/cad/x86-64_linux30/mentor/questaCDC/V10.4f_5/linux_x86_64/bin/qcdc -c -licq -do run.tcl");
xterm was able to start, however it stopped when executing the setenv, after that i tried with the new command by replacing the setenv with $ENV
system("xterm","-hold", "-e", "\$ENV{ZI_LIBERTY_IGNORE_CONSTRUCT_FILES} = \"$RAW_RF_DIR/lib/lib2v/qcdc_ignore\"", "setenv HOME_0IN /p/hdk/rtl/cad/x86-64_linux26/mentor/questaCDC/V10.4g_5/linux_x86_64", "modpath -n 1 \$HOME_0IN/bin", "modpath -n 1 \$HOME_0IN/modeltech/bin", "/p/hdk/rtl/cad/x86-64_linux30/mentor/questaCDC/V10.4f_5/linux_x86_64/bin/qcdc -c -licq -do run.tcl");
Here is the error message showing up in the new xterm (same for both approach)
Can't execvp $ENV{ZI_LIBERTY_IGNORE_CONSTRUCT_FILES} = "/nfs/fm/stod/stod4003/w.eew.100/rf_uprev_model_2020ww14p1//subIP/hip/MTLM_SA/RF.1//lib/lib2v/qcdc_ignore": No such file or directory
Please advise that how to make the series of operation works in the new xterm? Thanks!
-Eric-
The program run with -e must be a program, not a shell built-in like setenv. Off the top of my head, I can think of two solutions:
Set the environment variables before starting xterm. They would then be inherited by xterm.
Let the program run by xterm be a shell, and use that shell to set the environment variables and launch the tool. Something like this (untested):
system("xterm", "-e", "/bin/sh", "-c", "FOO=bar; FIE=fum; /run/my/program");
According to the man page I read, the following is the syntax of the -e option:
-e program [ arguments ... ]
It takes a path to a program, and optionally arguments to pass to that program. Specifically, it doesn't take a shell command. (It would be bad to accept a shell command without having the user specify for which shell!) That doesn't preclude one from running a shell command, though. This simply requires launching a shell, as the following does:
xterm -e sh -c shell_cmd
Solution:
my $script = <<'__EOS__';
export ZI_LIBERTY_IGNORE_CONSTRUCT_FILES="$RAW_RF_DIR/lib/lib2v/qcdc_ignore"
export HOME_0IN=/p/hdk/rtl/cad/x86-64_linux26/mentor/questaCDC/V10.4g_5/linux_x86_64
modpath -n 1 "$HOME_0IN/bin"
modpath -n 1 "$HOME_0IN/modeltech/bin"
/p/hdk/rtl/cad/x86-64_linux30/mentor/questaCDC/V10.4f_5/linux_x86_64/bin/qcdc -c -licq -do run.tcl
__EOS__
system("xterm", "-hold", "-e", "sh", "-c", $script)
Since a process normally passes a copy of its env vars to process it creates, you could also write the above as follows:
local $ENV{ZI_LIBERTY_IGNORE_CONSTRUCT_FILES} = "$ENV{RAW_RF_DIR}/lib/lib2v/qcdc_ignore";
local $ENV{HOME_0IN} = "/p/hdk/rtl/cad/x86-64_linux26/mentor/questaCDC/V10.4g_5/linux_x86_64";
my $script = <<'__EOS__';
modpath -n 1 "$HOME_0IN/bin"
modpath -n 1 "$HOME_0IN/modeltech/bin"
/p/hdk/rtl/cad/x86-64_linux30/mentor/questaCDC/V10.4f_5/linux_x86_64/bin/qcdc -c -licq -do run.tcl
__EOS__
system("xterm", "-hold", "-e", "sh", "-c", $script)
You can use csh similarly; I'm simply more familiar with sh.

How do I provide a command-line option to emacsclient?

I start emacsclient using:
emacsclient -a "" -c
This opens a frame connected to the emacs daemon, and starts the daemon if it's not already started. Great, this works fine.
However, I like opening my emacs frames maximized. With emacs, I would use -mm. However, that doesn't work with emacsclient. How do I make this work?
(It seems I could make something work by adding a shell file like so: emacsclient -a "myshell.sh" -c, where the shell file is: emacs -mm, but I haven't been able to make that work - the server doesn't stay up.)
You can add the following line to .emacs, so that Emacs can be started with the window maximized. See http://www.gnu.org/software/emacs/manual/html_node/elisp/Size-Parameters.html#Size-Parameters for details.
(add-to-list 'default-frame-alist '(fullscreen . maximized))
Emacs client accepts -F option, where you can specify frame parameters, so the above example would be:
emacsclient -c -a "" -F "((fullscreen . maximized))"
Let's say you want to run emacsclient fullscreen, which was my case.
man emacsclient shows emacsclient has -F option:
-F, --frame-parameters=ALIST
set the parameters of a newly-created frame.
In Emacs Manual, which is an info file, section (emacs) emacsclient Options has more information. Specifically for this question (elisp) Size Parameters mentions fullscreen parameter. To run emacsclient fullscreen, you need to supply an alist, with one element being (fullscreen . fullboth) like that:
emacsclient -c -F "((fullscreen . fullboth))"
emacsclient provides the --eval (-e for short) command line option for executing arbitrary Emacs Lisp code, so you can visit a file and call suspend-frame from the command line like so:
emacsclient -a "" -c --eval "(progn (find-file \"/tmp/my-file\") (suspend-frame))"
You could put this in a script, e.g:
#!/bin/bash
emacsclient -a "" -c --eval "(progn (find-file \"$1\") (suspend-frame))"

Emacs - connect to daemon (if it exists) without using emacsclient

If I have emacs running as a daemon on my system, I can connect to it easily using emacsclient. This I know. However, what I would like to know is, is there a way to tell emacs (not emacsclient) to behave like emacsclient if a daemon is already running?
e.g.
# emacs daemon is not running
emacs # should start a new frame
# ...
# emacs daemon IS running
emacs # should actually behave like emacsclient, i.e. connect to my daemon
Is there anything I can do to my init.el to replicate this kind of behaviour?
I don't think so, but can you achieve a similar effect by using emacsclient with an empty string as the the --alternate-editor option? From http://www.gnu.org/s/libtool/manual/emacs/emacsclient-Options.html#emacsclient-Options:
-a command
--alternate-editor=command
.
.
.
As a special exception, if command is the empty string, then emacsclient starts Emacs in daemon mode and then tries connecting again.
You can do the -a '' thing with emacsclient but what I do and a lot of people do is to have some kind of script that basically does what emacsclient '' does in multiple steps.
My version is something like this BASH script: The part you are interested in is the ensure-server-is-running function. This is the "main function" of the script, what follows is the ensure-server-is-running function and the rest is there after that for your curiosity but does not contribute to answering the question.
#!/bin/bash
# ec.sh
#
# [function definitions]
#
ensure-server-is-running
ensure-frame-exists
focus-current-frame
Ensuring that the server is running
# ec.sh function definition
# From https://emacs.stackexchange.com/a/12896/19972
function server-is-running() {
emacsclient -e '(+ 1 0)' > /dev/null 2>&1
}
function ensure-server-is-running(){
if ! server-is-running ; then
echo "Need to start daemon, press enter to continue, C-c to abort"
read
emacs --daemon
fi
}
And the other two function:
# ec.sh function definition
# From https://superuser.com/a/862809
function frame-exists() {
emacsclient -n -e "(if (> (length (frame-list)) 1) 't)" 2>/dev/null | grep -v nil >/dev/null 2>&1
}
function ensure-frame-exists() {
if ! frame-exists ; then
emacsclient -c --no-wait
fi
}
# From https://emacs.stackexchange.com/a/54139/19972
function focus-current-frame() {
# Doesn't work a frame exists and is in a terminal
emacsclient --eval "(progn (select-frame-set-input-focus (selected-frame)))"
}
focus-current-frame is something that will make the OS put you in the current Emacs Frame. This is the most important feature. For me I insert an adapted version of this into a MacOS Automator app. When there is an emacs GUI frame, doing Spotlight Search "EmacsC" (usually just typing the "e" is enough), puts me in my emacs window. It's a super fast way of switching to an emacs window.
Here's what I do. It's like the solution by #philippe-carpin, in the sense that it's a script that does multiple steps:
If emacs daemon is not running: start it, create a frame
If daemon but no frame: create a frame
If daemon with frame: focus that frame
In all cases you can pass filename(s) that will be opened.
In addition, my script only tries to run a piece of elisp just once and if there's no daemon it will not start an emacs process to run that elisp. So it should be slightly faster.
get_emacs_daemon_state () {
emacs_get_state_script='(if (> (length (frame-list)) 1) "daemon-with-frame" "daemon-no-frame")'
emacsclient -e "$emacs_get_state_script" -a "echo no-daemon" 2>/dev/null |
tr -d \" | cut -d' ' -f1
}
state=$(get_emacs_daemon_state)
create_frame_arg=""
if [[ $state = no-daemon ]]; then
emacs --daemon
fi
if [[ $state != daemon-with-frame ]]; then
create_frame_arg="--create-frame"
fi
client="emacsclient --no-wait $create_frame_arg"
if [[ $# -gt 0 ]]; then
# open files passed as arguments
$client "$#"
else
# if no file passed, we just focus the frame
$client --eval "(select-frame-set-input-focus (selected-frame))" >/dev/null
fi

Check if program is in path

Can sh itself check if a program exists or is in path?
I.e., not with the help of the "which" program.
I don't believe sh can directly. But perhaps something like:
which() {
save_IFS=$IFS
IFS=:
for d in $PATH; do
test -x $d/$1 && echo $d/$1
done
IFS=$save_IFS
}
and here's a nice variation that uses a subshell so that restoring IFS is not necessary:
which() (
IFS=:
for d in $PATH; do
test -x $d/$1 && echo $d/$1
done
)
Also, (in bash) if the command has been executed in the past and bash has already done the PATH search, you can see what it found with hash -t.
bash-3.2$ hash -t which
bash: hash: which: not found
bash-3.2$ which foo
bash-3.2$ hash -t which
/usr/bin/which
The utility command -v $CMD is apparently a portable option (in the sense of being part of POSIX); see also the very similar (though bash-specific) question, in particular this answer.