Multi line command to os.system - python-3.x

There may be something obvious that I'm missing here but searching google/so has not provided anything useful.
I'm writing a python script utilizes tkinter's filedialog.askopenfilename to open a file picker. Without getting into to much detail, I have the following line, which serves to bring the file picker to the front of the screen (taken directly from this helpful answer):
os.system('''/usr/bin/osascript -e 'tell app "Finder" to set frontmost of process "Python" to true' ''')
As you can see from the above code snippet, this line is too long for pep8 guidelines and I'd like to break it down.
However, despite my best efforts I can't seem to get it to split. This is due (I think) to the fact that the line contains both single and double quotes, and unfortunately os.system seems to insist on it being a single line.
I've tried
Triple quotes
String literal patching (\ at end, and + at beginning of each line)
Triple quotes on a per line basis
If it's relevant: using OSX and running python 3.6.4.
What is the correct (and ideally, minimal) way to go about breaking this line down?

Using the much improved subprocess module is usually a much better, more powerful, and safer way to call an external executable.
You can of course pass variables with \n in them as the arguments as well.
Note, the double (()) are because the first parameter is a tuple.
import subprocess
subprocess.call((
'/usr/bin/osascript',
'-e',
'tell app "Finder" to set frontmost of process "Python" to true',
))
There are at times reasons to call through the shell, but not usually.
https://docs.python.org/3.6/library/subprocess.html

Related

How not to escape an ampersand with python subprocess

I'd like to execute with subprocess.Popen() this command containing an ampersand to be interpreted as a batch concatenation operator:
COMMAND="c:\p\a.exe & python run.py"
subprocess.Popen(COMMAND,cwd=wd,shell=False)`
The ampersand & however is interpreted as an argument of a.exe and not as a batch operator.
Solution 1: Having seen the related question, a solution could be to set shell=True but that gives the error 'UNC path are not supported', since my working directory is remote. This solution does not work as it is.
Solution2: The executable a.exe should take a -inputDir parameter to specify the remote location of the files and use a local working directory. I think this solution could work but I may not have the source code of the executable.
Solution3: I could instead write c:\p\a.exe & python run.py into command.bat and then use
COMMAND="c:\p\command.bat"
subprocess.Popen(COMMAND,cwd=wd,shell=False)`
Could this approach work?
Solution4: I am trying to solve this changing only the subprocess.Popen() call. Is it possible to do it? Based on the python Popen doc I suspect is not possible. Please tell me I am wrong.
See also this related questions.
UPDATE:
Solution 5: #mata suggested to use Powershell Popen(['powershell', '-Command', r'C:\p\a.exe; python run.py']). This actually works, but now I have to deal with slightly different commands, and being lazy I've decided to use solution 3.
My favourite solution was Solution 3, to create a .bat file and call it
COMMAND="c:\p\command.bat"
subprocess.Popen(COMMAND,cwd=wd,shell=False)
I would use Solution 3
The & character is used to separate multiple commands on one command line.
Cmd.exe runs the first command, and then the second command.
In this case you could just write your batch file like this:
#echo off
c:\p\a.exe
python run.py
Also, it's worth noting when using cmd.exe:
The ampersand (&), pipe (|), and parentheses ( ) are special characters
that must be preceded by the escape character (^) or quotation marks
when you pass them as arguments.

How to accept the 'Did you mean?' terminal/git suggestion

This is a simple question.
Sometimes on a Terminal when you make a small mistake the console asks ¿Did you mean ...? - ¿Is there a way to quicky accept the suggestion?.
For example:
$ git add . -all
error: did you mean `--all` (with two dashes ?)
Is there a command that repeats the last line, but with the two dashes?
If you forget to write sudo, you can just do sudo !! and it will solve your problem. I want to know if there is something similar but for the error: did you mean case.
In the case of...
$ git add . -all
error: did you mean `--all` (with two dashes ?)
...the message is written by git directly to the terminal. This means that bash has no way of knowing what message was written; it would be literally impossible to implement anything in the shell that could automate putting that correction in place without making programs run under the shell considerably less efficient (by routing their output through the shell rather than directly to the terminal) and changing their behavior (if they ever call isatty() on their stdout or stderr).
That said, you can certainly run
^-all^--all
...if you haven't turned history expansion off, as with set +H (if off, it can be reenabled with set -H). I typically do turn this functionality off, myself; it's often more trouble than it's worth (making commands which would work perfectly well in scripts break in interactive shells when they use characters that history expansion is sensitive to, particularly !).

How to use a properties file that contains numbers properties in shell

This is my first question on StackOverflow. I am pretty sure it would have been answered already (it is a pretty dumb question, I think, as I just started to learn Linux scripting), but I did'nt succeed to find an answer yet.
Sorry for that.
Here is my problem: I try to use in a shell a number given in a property file, I have an error because the number is not taken "as it is".
I have a prop.properties file :
sleepTimeBeforeLoop=10
and a test.sh shell :
#!/bin/sh
. prop.properties
echo "time="$sleepTimeBeforeLoop
sleep $sleepTimeBeforeLoop
When I launch test.sh I have the following Output:
time=10
sleep: invalid time interval `10\r'
Try `sleep --help' for more information.
What I understand is that my properties files was correctly sourced, but that the property was taken as a string, with some special character to indicate the end of the line, or whatever.
How can I do to take only the "10" value?
Thank you in advance for your answer.
This is line endings issue / make sure your script files are terminated by \n (the unix way)
eg. write it in UNIX text editor or use a windows one capable of saving in "unix style"

Bash (or other shell): wrap all commands with function/script

Edit: This question was originally bash specific. I'd still rather have a bash solution, but if there's a good way to do this in another shell then that would be useful to know as well!
Okay, top level description of the problem. I would like to be able to add a hook to bash such that, when a user enters, for example $cat foo | sort -n | less, this is intercepted and translated into wrapper 'cat foo | sort -n | less'. I've seen ways to run commands before and after each command (using DEBUG traps or PROMPT_COMMAND or similar), but nothing about how to intercept each command and allow it to be handled by another process. Is there a way to do this?
For an explanation of why I'd like to do this, in case people have other suggestions of ways to approach it:
Tools like script let you log everything you do in a terminal to a log (as, to an extent, does bash history). However, they don't do it very well - script mixes input with output into one big string and gets confused with applications such as vi which take over the screen, history only gives you the raw commands being typed in, and neither of them work well if you have commands being entered into multiple terminals at the same time. What I would like to do is capture much richer information - as an example, the command, the time it executed, the time it completed, the exit status, the first few lines of stdin and stdout. I'd also prefer to send this to a listening daemon somewhere which could happily multiplex multiple terminals. The easy way to do this is to pass the command to another program which can exec a shell to handle the command as a subprocess whilst getting handles to stdin, stdout, exit status etc. One could write a shell to do this, but you'd lose much of the functionality already in bash, which would be annoying.
The motivation for this comes from trying to make sense of exploratory data analysis like procedures after the fact. With richer information like this, it would be possible to generate decent reporting on what happened, squashing multiple invocations of one command into one where the first few gave non-zero exits, asking where files came from by searching for everything that touched the file, etc etc.
Run this bash script:
#!/bin/bash
while read -e line
do
wrapper "$line"
done
In its simplest form, wrapper could consist of eval "$LINE". You mentioned wanting to have timings, so maybe instead have time eval "$line". You wanted to capture exit status, so this should be followed by the line save=$?. And, you wanted to capture the first few lines of stdout, so some redirecting is in order. And so on.
MORE: Jo So suggests that handling for multiple-line bash commands be included. In its simplest form, if eval returns with "syntax error: unexpected end of file", then you want to prompt for another line of input before proceeding. Better yet, to check for proper bash commands, run bash -n <<<"$line" before you do the eval. If bash -n reports the end-of-line error, then prompt for more input to add to `$line'. And so on.
Binfmt_misc comes to mind. The Linux kernel has a capability to allow arbitrary executable file formats to be recognized and passed to user application.
You could use this capability to register your wrapper but instead of handling arbitrary executable, it should handle all executable.

Redraw screen in terminal

How do some programs edit whats being displayed on the terminal (to pick a random example, the program 'sl')? I'm thinking of the Linux terminal here, it may happen in other OS's too, I don't know. I've always thought once some text was displayed, it stayed there. How do you change it without redrawing the entire screen?
Depending on the terminal you send control seuqences. Common sequences are for example esc[;H to send the cursor to a specific position (e.g. on Ansi, Xterm, Linux, VT100). However, this will vary with the type or terminal the user has ... curses (in conjunction with the terminfo files) will wrap that information for you.
Many applications make use of the curses library, or some language binding to it.
For rewriting on a single line, such as updating progress information, the special character "carriage return", often specified by the escape sequence "\r", can return the cursor to the start of the current line allowing subsequent output to overwrite what was previously written there.
try this shellscript
#!/bin/bash
i=1
while [ true ]
do
echo -e -n "\r $i"
i=$((i+1))
done
the -n options prevents the newline ... and the \r does the carriage return ... you write again and again into the same line - no scroling or what so ever
If you terminate a line sent to the terminal with a carriage return ('\r') instead of a linefeed ('\n'), it will move the cursor to the beginning of the current line, allowing the program to print more text over top of what it printed before. I use this occasionally for progress messages for long tasks.
If you ever need to do more terminal editing than that, use ncurses or a variant thereof.
There are characters that can be sent to the terminal that move the cursor back. Then text can be overwritten.
There is a list here. Note the "move cursor something" lines.
NCurses is a cross-platform library that lets you draw user interfaces on smart terminals.
Corporal Touchy has answered how this is done at the lowest level. For easier development the curses library gives a higher level of control than simply sending characters to the terminal.
To build on #Corporal Touchy's answer, there are libraries available that will handle some of this functionality for you such as curses/ncurses
I agree with danio, ncurses is the way to go. Here's a good tutorial:
http://tldp.org/HOWTO/NCURSES-Programming-HOWTO/

Resources