Full command line as it was typed

2019-01-15 05:48发布

I want to get the full command line as it was typed.

This:

" ".join(sys.argv[:])

doesn't work here (deletes double quotes). Also I prefer not to rejoin something that was parsed and split.

Any ideas?

7条回答
Ridiculous、
2楼-- · 2019-01-15 05:51

In a Unix environment, this is not generally possible...the best you can hope for is the command line as passed to your process.

Because the shell (essentially any shell) may munge the typed command line in several ways before handing it to the OS for execution.

查看更多
兄弟一词,经得起流年.
3楼-- · 2019-01-15 05:56

If you're on Linux, I'd suggest monkeying with the ~/.bash_history file or the shell history command, although I believe the command must finish executing before it's added to the shell history.

I started playing with:

import popen2
x,y = popen2.popen4("tail ~/.bash_history")
print x.readlines()

But I'm getting weird behavior where the shell doesn't seem to be completely flushing to the .bash_history file.

查看更多
beautiful°
4楼-- · 2019-01-15 05:58

Here's how you can do it from within the Python program to get back the full command string. Since the command-line arguments are already handled once before it's sent into sys.argv, this is how you can reconstruct that string.

commandstring = '';

for arg in sys.argv:
    if ' ' in arg:
        commandstring += '"{}"  '.format(arg);
    else:
        commandstring+="{}  ".format(arg);

print(commandstring);

Example:

Invoking like this from the terminal,

./saferm.py sdkf lsadkf -r sdf -f sdf -fs -s "flksjfksdkfj sdfsdaflkasdf"

will give the same string in commandstring:

./saferm.py sdkf lsadkf -r sdf -f sdf -fs -s "flksjfksdkfj sdfsdaflkasdf"
查看更多
该账号已被封号
5楼-- · 2019-01-15 05:59

You're too late. By the time that the typed command gets to Python your shell has already worked its magic. For example, quotes get consumed (as you've noticed), variables get interpolated, etc.

查看更多
迷人小祖宗
6楼-- · 2019-01-15 06:01

On Linux there is /proc/<pid>/cmdline that is in the format of argv[] (i.e. there is 0x00 between all the lines and you can't really know how many strings there are since you don't get the argc; though you will know it when the file runs out of data ;).

You can be sure that that commandline is already munged too since all escaping/variable filling is done and parameters are nicely packaged (no extra spaces between parameters, etc.).

查看更多
祖国的老花朵
7楼-- · 2019-01-15 06:03

*nix

Look at the initial stack layout (Linux on i386) that provides access to command line and environment of a program: the process sees only separate arguments.

You can't get the command-line as it was typed in the general case. On Unix, the shell parses the command-line into separate arguments and eventually execv(path, argv) function that invokes the corresponding syscall is called. sys.argv is derived from argv parameter passed to the execve() function. You could get something equivalent using " ".join(map(pipes.quote, argv)) though you shouldn't need to e.g., if you want to restart the script with slightly different command-line parameters then sys.argv is enough (in many cases), see Is it possible to set the python -O (optimize) flag within a script?

There are some creative (non-practical) solutions:

  • attach the shell using gdb and interrogate it (most shells are capable of repeating the same command twice)—you should be able to get almost the same command as it was typed— or read its history file directly if it is updated before your process exits
  • use screen, script utilities to get the terminal session
  • use a keylogger, to get what was typed.

Windows

On Windows the native CreateProcess() interface is a string but python.exe still receives arguments as a list. subprocess.list2cmdline(sys.argv) might help to reverse the process. list2cmdline is designed for applications using the same rules as the MS C runtimepython.exe is one of them. list2cmdline doesn't return the command-line as it was typed but it returns a functional equivalent in this case.

On Python 2, you might need GetCommandLineW(), to get Unicode characters from the command line that can't be represented in Windows ANSI codepage (such as cp1252).

查看更多
登录 后发表回答