Why does `ipython foo.py bar.py` only print `foo.py`'s output? - ipython

The IPython 0.13.1 documentation says:
$ ipython -h
...
Usage
ipython [subcommand] [options] [files]
If invoked with no options, it executes all the files listed in sequence
and exits, use -i to enter interactive mode after running the files.
...
I have two files foo.py and bar.py.
foo.py:
print "Hi, I'm foo."
bar.py:
print "Hi, I'm bar."
I expect the following to print both files output, in the corresponding order. Instead I only get the output from the first file given on the command line.
$ ipython foo.py bar.py
Hi, I'm foo.
$ ipython bar.py foo.py
Hi, I'm bar.
Is that an implementation bug, a documentation bug, or user misunderstanding? If the latter, what should I do instead?

This is a documentation failure, fixed by this Pull Request.
The command
$> ipython [-i] script.py script2.py ...
behaves exactly the same as the command
$> python [-i] script.py script2.py ...
In that, script.py is run, with sys.argv of ['script.py', 'script2.py', '...'],
and if -i is specified, it drops into an interactive session after running the script.

Related

setup new database in ubuntu using a script [duplicate]

I have a script where I need to start a command, then pass some additional commands as commands to that command. I tried
su
echo I should be root now:
who am I
exit
echo done.
... but it doesn't work: The su succeeds, but then the command prompt is just staring at me. If I type exit at the prompt, the echo and who am i etc start executing! And the echo done. doesn't get executed at all.
Similarly, I need for this to work over ssh:
ssh remotehost
# this should run under my account on remotehost
su
## this should run as root on remotehost
whoami
exit
## back
exit
# back
How do I solve this?
I am looking for answers which solve this in a general fashion, and which are not specific to su or ssh in particular. The intent is for this question to become a canonical for this particular pattern.
Adding to tripleee's answer:
It is important to remember that the section of the script formatted as a here-document for another shell is executed in a different shell with its own environment (and maybe even on a different machine).
If that block of your script contains parameter expansion, command substitution, and/or arithmetic expansion, then you must use the here-document facility of the shell slightly differently, depending on where you want those expansions to be performed.
1. All expansions must be performed within the scope of the parent shell.
Then the delimiter of the here document must be unquoted.
command <<DELIMITER
...
DELIMITER
Example:
#!/bin/bash
a=0
mylogin=$(whoami)
sudo sh <<END
a=1
mylogin=$(whoami)
echo a=$a
echo mylogin=$mylogin
END
echo a=$a
echo mylogin=$mylogin
Output:
a=0
mylogin=leon
a=0
mylogin=leon
2. All expansions must be performed within the scope of the child shell.
Then the delimiter of the here document must be quoted.
command <<'DELIMITER'
...
DELIMITER
Example:
#!/bin/bash
a=0
mylogin=$(whoami)
sudo sh <<'END'
a=1
mylogin=$(whoami)
echo a=$a
echo mylogin=$mylogin
END
echo a=$a
echo mylogin=$mylogin
Output:
a=1
mylogin=root
a=0
mylogin=leon
3. Some expansions must be performed in the child shell, some - in the parent.
Then the delimiter of the here document must be unquoted and you must escape those expansion expressions that must be performed in the child shell.
Example:
#!/bin/bash
a=0
mylogin=$(whoami)
sudo sh <<END
a=1
mylogin=\$(whoami)
echo a=$a
echo mylogin=\$mylogin
END
echo a=$a
echo mylogin=$mylogin
Output:
a=0
mylogin=root
a=0
mylogin=leon
A shell script is a sequence of commands. The shell will read the script file, and execute those commands one after the other.
In the usual case, there are no surprises here; but a frequent beginner error is assuming that some commands will take over from the shell, and start executing the following commands in the script file instead of the shell which is currently running this script. But that's not how it works.
Basically, scripts work exactly like interactive commands, but how exactly they work needs to be properly understood. Interactively, the shell reads a command (from standard input), runs that command (with input from standard input), and when it's done, it reads another command (from standard input).
Now, when executing a script, standard input is still the terminal (unless you used a redirection) but the commands are read from the script file, not from standard input. (The opposite would be very cumbersome indeed - any read would consume the next line of the script, cat would slurp all the rest of the script, and there would be no way to interact with it!) The script file only contains commands for the shell instance which executes it (though you can of course still use a here document etc to embed inputs as command arguments).
In other words, these "misunderstood" commands (su, ssh, sh, sudo, bash etc) when run alone (without arguments) will start an interactive shell, and in an interactive session, that's obviously fine; but when run from a script, that's very often not what you want.
All of these commands have ways to accept commands by ways other than in an interactive terminal session. Typically, each command supports a way to pass it commands as options or arguments:
su root -c 'who am i'
ssh user#remote uname -a
sh -c 'who am i; echo success'
Many of these commands will also accept commands on standard input:
printf 'uname -a; who am i; uptime' | su
printf 'uname -a; who am i; uptime' | ssh user#remote
printf 'uname -a; who am i; uptime' | sh
which also conveniently allows you to use here documents:
ssh user#remote <<'____HERE'
uname -a
who am i
uptime
____HERE
sh <<'____HERE'
uname -a
who am i
uptime
____HERE
For commands which accept a single command argument, that command can be sh or bash with multiple commands:
sudo sh -c 'uname -a; who am i; uptime'
As an aside, you generally don't need an explicit exit because the command will terminate anyway when it has executed the script (sequence of commands) you passed in for execution.
If you want a generic solution which will work for any kind of program, you can use the expect command.
Extract from the manual page:
Expect is a program that "talks" to other interactive programs according to a script. Following the script, Expect knows what can be expected from a program and what the correct response should be. An interpreted language provides branching and high-level control structures to direct the dialogue. In addition, the user can take control and interact directly when desired, afterward returning control to the script.
Here is a working example using expect:
set timeout 60
spawn sudo su -
expect "*?assword" { send "*secretpassword*\r" }
send_user "I should be root now:"
expect "#" { send "whoami\r" }
expect "#" { send "exit\r" }
send_user "Done.\n"
exit
The script can then be launched with a simple command:
$ expect -f custom.script
You can view a full example in the following page: http://www.journaldev.com/1405/expect-script-example-for-ssh-and-su-login-and-running-commands
Note: The answer proposed by #tripleee would only work if standard input could be read once at the start of the command, or if a tty had been allocated, and won't work for any interactive program.
Example of errors if you use a pipe
echo "su whoami" |ssh remotehost
--> su: must be run from a terminal
echo "sudo whoami" |ssh remotehost
--> sudo: no tty present and no askpass program specified
In SSH, you might force a TTY allocation with multiple -t parameters, but when sudo will ask for the password, it will fail.
Without the use of a program like expect any call to a function/program which might get information from stdin will make the next command fail:
ssh use#host <<'____HERE'
echo "Enter your name:"
read name
echo "ok."
____HERE
--> The `echo "ok."` string will be passed to the "read" command

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 to run perl test in debugger mode?

I try to run test under debugger as:
perl -d $(which prove) t/file.t
But this has no effect because each test is run as separate job.
I have found --exec option, but when I provide it I lost any option from .proverc file and command line
prove -Ithis/is/lost --exec 'perl -d' t/file.t
How to run tests by prove with additional options and do not lose those options which were provided at .proverc file and command line?
I do not want repeat myself and write:
prove --exec 'perl -d -Ilib -Ilocal/lib/perl5' t/file.t
While -Ilib and -Ilocal/lib/perl5 are both at .proverc file
You can repeat yourself once if you set the PERL5OPT environment variable.
export DBG_MODE='-d -Ilib -Ilocal/lib/perl5'
prove t/file1.t # regular use
PERL5OPT=$DBG_MODE prove t/file2.t # with debugger
or with an alias or bash function
alias proved='PERL5OPT="-d -Ilib -Ilocal/lib/perl5" prove'

A change of shebang + eval leads to the perl script failure

This is a question derives from another post. Based upon the comments and answer from that post, I change the following shebang + eval into another one:
Old works version
#!/bin/perl
eval 'exec perl5 -S $0 ${1+"$#"}'
if 0;
New doesn't work version
#!/bin/sh
eval 'exec perl5 -S $0 ${1+"$#"}'
if 0;
Notice that I change #!/bin/perl to #!/bin/sh and based upon my understanding, the new version should also work because the script is treated like shell script and eval get executed and perl5 is invoked to use perl to execute the same script. However, when I actually run this, I got:
/bin/sh: -S: invalid option
Can anyone explain why this case the script is failed. Do I misunderstand something? I'm using ksh
Also this web page I found online seems suggest that my new version should work as well.
Thanks much!
From the Perl documentation:
If the #! line does not contain the word "perl" nor the word "indir", the program named after the #! is executed instead of the Perl interpreter. This is slightly bizarre, but it helps people on machines that don't do #!, because they can tell a program that their SHELL is /usr/bin/perl, and Perl will then dispatch the program to the correct interpreter for them.
So if you launch the modified version as ./script:
Your shell executes ./script
The kernel actually executes /bin/sh ./script
sh executes perl5 -S ./script
perl5 executes /bin/sh -S ./script because it sees a shebang that doesn't contain perl.
sh dies because it doesn't recognize the -S option.
And if you launch the modified version as perl5 script:
Your shell executes perl5 script
perl5 executes /bin/sh -S script because it sees a shebang that doesn't contain perl.
sh dies because it doesn't recognize the -S option.
Also this web page I found online seems suggest that my new version should work as well.
The code on that page is significantly different than the code you used. In that code, there's an explicit instruction (-x) to ignore the actual shebang line, and to look for one that contains perl later in the file (which is also missing from your code).

Call a Mathematica program from the command line, with command-line args, stdin, stdout, and stderr

If you have Mathematica code in foo.m, Mathematica can be invoked with -noprompt
and with -initfile foo.m
(or -run "<<foo.m")
and the command line arguments are available in $CommandLine (with extra junk in there) but is there a way to just have some mathematica code like
#!/usr/bin/env MathKernel
x = 2+2;
Print[x];
Print["There were ", Length[ARGV], " args passed in on the command line."];
linesFromStdin = readList[];
etc.
and chmod it executable and run it? In other words, how does one use Mathematica like any other scripting language (Perl, Python, Ruby, etc)?
MASH -- Mathematica Scripting Hack -- will do this.
Since Mathematica version 6, the following perl script suffices:
http://ai.eecs.umich.edu/people/dreeves/mash/mash.pl
For previous Mathematica versions, a C program is needed:
http://ai.eecs.umich.edu/people/dreeves/mash/pre6
UPDATE: At long last, Mathematica 8 supports this natively with the "-script" command-line option:
http://www.wolfram.com/mathematica/new-in-8/mathematica-shell-scripts/
Here is a solution that does not require an additional helper script. You can use the following shebang to directly invoke the Mathematica kernel:
#!/bin/sh
exec <"$0" || exit; read; read; exec /usr/local/bin/math -noprompt "$#" | sed '/^$/d'; exit
(* Mathematica code starts here *)
x = 2+2;
Print[x];
The shebang code skips the first two lines of the script and feeds the rest to the Mathematica kernel as standard input. The sed command drops empty lines produced by the kernel.
This hack is not as versatile as MASH. Because the Mathematica code is read from stdin you cannot use stdin for user input, i.e., the functions Input and InputString do not work.
Assuming you add the Mathematica binaries to the PATH environment variable in ~/.profile,
export PATH=$PATH:/Applications/Mathematica.app/Contents/MacOS
Then you just write this shebang line in your Mathematica scripts.
#!/usr/bin/env MathKernel -script
Now you can dot-slash your scripts.
$ cat hello.ma
#!/usr/bin/env MathKernel -script
Print["Hello World!"]
$ chmod a+x hello.ma
$ ./hello.ma
"Hello World!"
Tested with Mathematica 8.0.
Minor bug: Mathematica surrounds Print[s] with quotes in Windows and Mac OS X, but not Linux. WTF?
Try
-initfile filename
And put the exit command into your program
I found another solution that worked for me.
Save the code in a .m file, then run it like this: MathKernel -noprompt -run “<
This is the link: http://bergmanlab.smith.man.ac.uk/?p=38
For mathematica 7
$ cat test.m
#!/bin/bash
MathKernel -noprompt -run < <( cat $0| sed -e '1,4d' ) | sed '1d'
exit 0
### code start Here ... ###
Print["Hello World!"]
X=7
X*5
Usage:
$ chmod +x test.m
$ ./test.m
"Hello World!"
7
35