标签归档:shell

人们为什么在Python脚本的第一行上编写#!/ usr / bin / env python shebang?

问题:人们为什么在Python脚本的第一行上编写#!/ usr / bin / env python shebang?

在我看来,如果没有该行,文件运行相同。

It seems to me like the files run the same without that line.


回答 0

如果您安装了多个版本的Python,请/usr/bin/env确保使用的解释器是您环境中的第一个解释器$PATH。另一种方法是对类似的东西进行硬编码#!/usr/bin/python;可以,但是不太灵活。

在Unix中,要解释的可执行文件可以通过#!在第一行的开头加上,然后是解释器(及其可能需要的任何标志)来指示要使用的解释器。

当然,如果您在谈论其他平台,则此规则不适用(但“ shebang行”没有害处,并且如果您将该脚本复制到具有 Unix基础的平台(例如Linux,Mac),将有帮助等)。

If you have several versions of Python installed, /usr/bin/env will ensure the interpreter used is the first one on your environment’s $PATH. The alternative would be to hardcode something like #!/usr/bin/python; that’s ok, but less flexible.

In Unix, an executable file that’s meant to be interpreted can indicate what interpreter to use by having a #! at the start of the first line, followed by the interpreter (and any flags it may need).

If you’re talking about other platforms, of course, this rule does not apply (but that “shebang line” does no harm, and will help if you ever copy that script to a platform with a Unix base, such as Linux, Mac, etc).


回答 1

那就是shebang线。如Wikipedia条目所述

在计算中,shebang(也称为“ hashbang”,“ hashhpling”,“ bang bang”或“ crunchbang”)是指字符“#!”。当它们是解释器指令中的前两个字符作为文本文件的第一行时。在类似Unix的操作系统中,程序加载器将这两个字符的存在指示为文件是脚本,并尝试使用文件中第一行其余部分指定的解释器执行该脚本。

另请参见Unix FAQ条目

即使在Windows上,shebang行不能确定要运行的解释程序,也可以通过在shebang行上指定选项来将选项传递给解释程序。我发现在一次性脚本中保留通用的shebang行很有用(例如我在回答SO问题时编写的脚本),因此我可以在Windows和ArchLinux上快速对其进行测试。

使用env实用程序可以在路径上调用命令:

剩下的第一个参数指定要调用的程序名称;根据PATH环境变量进行搜索。任何剩余的参数将作为参数传递给该程序。

That is called the shebang line. As the Wikipedia entry explains:

In computing, a shebang (also called a hashbang, hashpling, pound bang, or crunchbang) refers to the characters “#!” when they are the first two characters in an interpreter directive as the first line of a text file. In a Unix-like operating system, the program loader takes the presence of these two characters as an indication that the file is a script, and tries to execute that script using the interpreter specified by the rest of the first line in the file.

See also the Unix FAQ entry.

Even on Windows, where the shebang line does not determine the interpreter to be run, you can pass options to the interpreter by specifying them on the shebang line. I find it useful to keep a generic shebang line in one-off scripts (such as the ones I write when answering questions on SO), so I can quickly test them on both Windows and ArchLinux.

The env utility allows you to invoke a command on the path:

The first remaining argument specifies the program name to invoke; it is searched for according to the PATH environment variable. Any remaining arguments are passed as arguments to that program.


回答 2

进一步扩展其他答案,这是一个小示例,说明了如何谨慎使用/usr/bin/envshebang行会导致命令行脚本出现问题:

$ /usr/local/bin/python -V
Python 2.6.4
$ /usr/bin/python -V
Python 2.5.1
$ cat my_script.py 
#!/usr/bin/env python
import json
print "hello, json"
$ PATH=/usr/local/bin:/usr/bin
$ ./my_script.py 
hello, json
$ PATH=/usr/bin:/usr/local/bin
$ ./my_script.py 
Traceback (most recent call last):
  File "./my_script.py", line 2, in <module>
    import json
ImportError: No module named json

json模块在Python 2.5中不存在。

防止此类问题的一种方法是使用大多数Python通常安装的版本化python命令名称:

$ cat my_script.py 
#!/usr/bin/env python2.6
import json
print "hello, json"

如果您只需要区分Python 2.x和Python 3.x,Python 3的最新版本还提供了一个python3名称:

$ cat my_script.py 
#!/usr/bin/env python3
import json
print("hello, json")

Expanding a bit on the other answers, here’s a little example of how your command line scripts can get into trouble by incautious use of /usr/bin/env shebang lines:

$ /usr/local/bin/python -V
Python 2.6.4
$ /usr/bin/python -V
Python 2.5.1
$ cat my_script.py 
#!/usr/bin/env python
import json
print "hello, json"
$ PATH=/usr/local/bin:/usr/bin
$ ./my_script.py 
hello, json
$ PATH=/usr/bin:/usr/local/bin
$ ./my_script.py 
Traceback (most recent call last):
  File "./my_script.py", line 2, in <module>
    import json
ImportError: No module named json

The json module doesn’t exist in Python 2.5.

One way to guard against that kind of problem is to use the versioned python command names that are typically installed with most Pythons:

$ cat my_script.py 
#!/usr/bin/env python2.6
import json
print "hello, json"

If you just need to distinguish between Python 2.x and Python 3.x, recent releases of Python 3 also provide a python3 name:

$ cat my_script.py 
#!/usr/bin/env python3
import json
print("hello, json")

回答 3

为了运行python脚本,我们需要告诉shell三件事:

  1. 该文件是一个脚本
  2. 我们要执行哪个解释器的脚本
  3. 口译员的路径

射手#!完成(1.)。shebang以a开头,#因为该#字符在许多脚本语言中都是注释标记。因此,解释器会自动忽略shebang行的内容。

env命令完成(2.)和(3.)。引用“草率”

env命令的常见用法是通过利用env将在$ PATH中搜索被告知要启动的命令的事实来启动解释器。由于shebang行需要指定绝对路径,并且由于各种解释器(perl,bash,python)的位置可能相差很大,因此通常使用:

#!/usr/bin/env perl  而不是尝试猜测它是/ bin / perl,/ usr / bin / perl,/ usr / local / bin / perl,/ usr / local / pkg / perl,/ fileserver / usr / bin / perl还是/ home用户系统上的/ MrDaniel / usr / bin / perl …

另一方面,env几乎总是位于/ usr / bin / env中。(除非不是这种情况;某些系统可能使用/ bin / env,但这是一种相当罕见的情况,仅在非Linux系统上发生。)

In order to run the python script, we need to tell the shell three things:

  1. That the file is a script
  2. Which interpreter we want to execute the script
  3. The path of said interpreter

The shebang #! accomplishes (1.). The shebang begins with a # because the # character is a comment marker in many scripting languages. The contents of the shebang line are therefore automatically ignored by the interpreter.

The env command accomplishes (2.) and (3.). To quote “grawity,”

A common use of the env command is to launch interpreters, by making use of the fact that env will search $PATH for the command it is told to launch. Since the shebang line requires an absolute path to be specified, and since the location of various interpreters (perl, bash, python) may vary a lot, it is common to use:

#!/usr/bin/env perl  instead of trying to guess whether it is /bin/perl, /usr/bin/perl, /usr/local/bin/perl, /usr/local/pkg/perl, /fileserver/usr/bin/perl, or /home/MrDaniel/usr/bin/perl on the user’s system…

On the other hand, env is almost always in /usr/bin/env. (Except in cases when it isn’t; some systems might use /bin/env, but that’s a fairly rare occassion and only happens on non-Linux systems.)


回答 4

也许您的问题是这样的:

如果要使用: $python myscript.py

您根本不需要那条线。系统将调用python,然后python解释器将运行您的脚本。

但是,如果您打算使用: $./myscript.py

像普通程序或bash脚本一样直接调用它,您需要编写该行以向系统指定运行该程序的程序(并使其通过可执行chmod 755

Perhaps your question is in this sense:

If you want to use: $python myscript.py

You don’t need that line at all. The system will call python and then python interpreter will run your script.

But if you intend to use: $./myscript.py

Calling it directly like a normal program or bash script, you need write that line to specify to the system which program use to run it, (and also make it executable with chmod 755)


回答 5

execLinux内核的系统调用#!本身了解shebangs()

当您进行bash操作时:

./something

在Linux上,这会exec使用path 调用系统调用./something

内核的这一行在传递给exec以下文件的文件上调用:https : //github.com/torvalds/linux/blob/v4.8/fs/binfmt_script.c#L25

if ((bprm->buf[0] != '#') || (bprm->buf[1] != '!'))

它读取文件的头几个字节,并将其与进行比较#!

如果比较结果为真,那么Linux内核将解析其余的行,这将exec使用路径/usr/bin/env python和当前文件作为第一个参数进行另一个调用:

/usr/bin/env python /path/to/script.py

这适用于任何#用作注释字符的脚本语言。

是的,您可以使用以下方法进行无限循环:

printf '#!/a\n' | sudo tee /a
sudo chmod +x /a
/a

Bash识别错误:

-bash: /a: /a: bad interpreter: Too many levels of symbolic links

#! 只是碰巧是人类可读的,但这不是必需的。

如果文件以不同的字节开头,则exec系统调用将使用其他处理程序。另一个最重要的内置处理程序是用于ELF可执行文件:https : //github.com/torvalds/linux/blob/v4.8/fs/binfmt_elf.c#L1305检查字节7f 45 4c 46(也恰好是人的)可读.ELF)。让我们通过读取的4个前字节来确认/bin/ls,这是ELF可执行文件:

head -c 4 "$(which ls)" | hd 

输出:

00000000  7f 45 4c 46                                       |.ELF|
00000004                                                                 

因此,当内核看到这些字节时,它将获取ELF文件,将其正确地放入内存,并使用它开始一个新进程。另请参阅:内核如何获取在Linux下运行的可执行二进制文件?

最后,您可以使用该binfmt_misc机制添加自己的shebang处理程序。例如,您可以.jarfiles添加自定义处理程序。该机制甚至通过文件扩展名支持处理程序。另一个应用程序是使用QEMU透明地运行不同体系结构的可执行文件

我不认为POSIX指定了shebangs:https ://unix.stackexchange.com/a/346214/32558 ,尽管它在基本原理部分中确实提到了,并且形式为“如果系统支持可执行脚本,则可能发生”。macOS和FreeBSD似乎也实现了它。

PATH 搜索动机

可能存在shebang的一个主要动机是,在Linux中,我们经常希望从以下命令运行命令PATH

basename-of-command

代替:

/full/path/to/basename-of-command

但是,如果没有shebang机制,Linux如何知道如何启动每种类型的文件?

在命令中对扩展进行硬编码:

 basename-of-command.py

或在每个解释器上实施PATH搜索:

python basename-of-command

这样做是有可能的,但这是一个主要问题,如果我们决定将命令重构为另一种语言,那么一切都会中断。

Shebangs很好地解决了这个问题。

The exec system call of the Linux kernel understands shebangs (#!) natively

When you do on bash:

./something

on Linux, this calls the exec system call with the path ./something.

This line of the kernel gets called on the file passed to exec: https://github.com/torvalds/linux/blob/v4.8/fs/binfmt_script.c#L25

if ((bprm->buf[0] != '#') || (bprm->buf[1] != '!'))

It reads the very first bytes of the file, and compares them to #!.

If the comparison is true, then the rest of the line is parsed by the Linux kernel, which makes another exec call with path /usr/bin/env python and current file as the first argument:

/usr/bin/env python /path/to/script.py

and this works for any scripting language that uses # as a comment character.

And yes, you can make an infinite loop with:

printf '#!/a\n' | sudo tee /a
sudo chmod +x /a
/a

Bash recognizes the error:

-bash: /a: /a: bad interpreter: Too many levels of symbolic links

#! just happens to be human readable, but that is not required.

If the file started with different bytes, then the exec system call would use a different handler. The other most important built-in handler is for ELF executable files: https://github.com/torvalds/linux/blob/v4.8/fs/binfmt_elf.c#L1305 which checks for bytes 7f 45 4c 46 (which also happens to be human readable for .ELF). Let’s confirm that by reading the 4 first bytes of /bin/ls, which is an ELF executable:

head -c 4 "$(which ls)" | hd 

output:

00000000  7f 45 4c 46                                       |.ELF|
00000004                                                                 

So when the kernel sees those bytes, it takes the ELF file, puts it into memory correctly, and starts a new process with it. See also: How does kernel get an executable binary file running under linux?

Finally, you can add your own shebang handlers with the binfmt_misc mechanism. For example, you can add a custom handler for .jar files. This mechanism even supports handlers by file extension. Another application is to transparently run executables of a different architecture with QEMU.

I don’t think POSIX specifies shebangs however: https://unix.stackexchange.com/a/346214/32558 , although it does mention in on rationale sections, and in the form “if executable scripts are supported by the system something may happen”. macOS and FreeBSD also seem to implement it however.

PATH search motivation

Likely, one big motivation for the existence of shebangs is the fact that in Linux, we often want to run commands from PATH just as:

basename-of-command

instead of:

/full/path/to/basename-of-command

But then, without the shebang mechanism, how would Linux know how to launch each type of file?

Hardcoding the extension in commands:

 basename-of-command.py

or implementing PATH search on every interpreter:

python basename-of-command

would be a possibility, but this has the major problem that everything breaks if we ever decide to refactor the command into another language.

Shebangs solve this problem beautifully.


回答 6

从技术上讲,在Python中,这只是一条注释行。

仅当您从外壳程序(从命令行)运行py脚本时才使用此行。这就是众所周知的射帮!” ,它可用于各种情况,而不仅限于Python脚本。

在这里,它指示shell启动特定版本的Python(以照顾文件的其余部分。

Technically, in Python, this is just a comment line.

This line is only used if you run the py script from the shell (from the command line). This is know as the Shebang!”, and it is used in various situations, not just with Python scripts.

Here, it instructs the shell to start a specific version of Python (to take care of the rest of the file.


回答 7

这样做的主要原因是使脚本可跨操作系统环境移植。

例如在mingw下,python脚本使用:

#!/c/python3k/python 

在GNU / Linux发行版中,它是:

#!/usr/local/bin/python 

要么

#!/usr/bin/python

在所有最佳的商业Unix sw / hw系统(OS / X)下,它是:

#!/Applications/MacPython 2.5/python

或在FreeBSD上:

#!/usr/local/bin/python

但是,所有这些差异都可以通过使用以下命令使脚本可移植到所有人中:

#!/usr/bin/env python

The main reason to do this is to make the script portable across operating system environments.

For example under mingw, python scripts use :

#!/c/python3k/python 

and under GNU/Linux distribution it is either:

#!/usr/local/bin/python 

or

#!/usr/bin/python

and under the best commercial Unix sw/hw system of all (OS/X), it is:

#!/Applications/MacPython 2.5/python

or on FreeBSD:

#!/usr/local/bin/python

However all these differences can make the script portable across all by using:

#!/usr/bin/env python

回答 8

强调大多数人错过的一件事可能是有道理的,这可能会阻止立即理解。当您输入python终端时,通常不会提供完整路径。而是在PATH环境变量中向上查找可执行文件。反过来,当您想直接执行Python程序时/path/to/app.py,必须告诉Shell使用什么解释器(通过hashbang,上面其他贡献者在解释什么)。

Hashbang希望有完整的口译员。因此,要直接运行Python程序,您必须提供Python二进制文件的完整路径,该路径有很大差异,尤其是考虑到使用virtualenv时。为了解决可移植性,/usr/bin/env使用了技巧。后者最初旨在就地更改环境并在其中运行命令。如果未提供任何更改,它将在当前环境中运行该命令,从而有效地导致执行该操作的相同PATH查找。

来自unix stackexchange的来源

It probably makes sense to emphasize one thing that the most have missed, which may prevent immediate understanding. When you type python in terminal you don’t normally provide a full path. Instead, the executable is up looked in PATH environment variable. In turn, when you want to execute a Python program directly, /path/to/app.py, one must tell the shell what interpreter to use (via the hashbang, what the other contributors are explaining above).

Hashbang expects full path to an interpreter. Thus to run your Python program directly you have to provide full path to Python binary which varies significantly, especially considering a use of virtualenv. To address portability the trick with /usr/bin/env is used. The latter is originally intended to alter environment in-place and run a command in it. When no alteration is provided it runs the command in current environment, which effectively results in the same PATH lookup which does the trick.

Source from unix stackexchange


回答 9

这是一个Shell约定,它告诉Shell哪个程序可以执行脚本。

#!/ usr / bin / env python

解析为Python二进制文件的路径。

This is a shell convention that tells the shell which program can execute the script.

#!/usr/bin/env python

resolves to a path to the Python binary.


回答 10

建议的方法,在文档中提出:

2.2.2。可执行Python脚本

在BSD式的Unix系统上,可以将Python脚本像shell脚本一样直接执行,方法是:

#! /usr/bin/env python3.2

来自http://docs.python.org/py3k/tutorial/interpreter.html#executable-python-scripts

It’s recommended way, proposed in documentation:

2.2.2. Executable Python Scripts

On BSD’ish Unix systems, Python scripts can be made directly executable, like shell scripts, by putting the line

#! /usr/bin/env python3.2

from http://docs.python.org/py3k/tutorial/interpreter.html#executable-python-scripts


回答 11

您可以使用virtualenv尝试此问题

这是test.py

#! /usr/bin/env python
import sys
print(sys.version)

创建虚拟环境

virtualenv test2.6 -p /usr/bin/python2.6
virtualenv test2.7 -p /usr/bin/python2.7

激活每个环境,然后检查差异

echo $PATH
./test.py

You can try this issue using virtualenv

Here is test.py

#! /usr/bin/env python
import sys
print(sys.version)

Create virtual environments

virtualenv test2.6 -p /usr/bin/python2.6
virtualenv test2.7 -p /usr/bin/python2.7

activate each environment then check the differences

echo $PATH
./test.py

回答 12

它只是指定您要使用的解释器。要理解这一点,可以通过在终端上创建一个文件touch test.py,然后在该文件中键入以下内容:

#!/usr/bin/env python3
print "test"

chmod +x test.py使你的脚本执行。之后,当您执行此操作时,./test.py将出现错误消息:

  File "./test.py", line 2
    print "test"
               ^
SyntaxError: Missing parentheses in call to 'print'

因为python3不支持print运算符。

现在继续并将代码的第一行更改为:

#!/usr/bin/env python2

并且可以正常工作,并打印test到stdout,因为python2支持print运算符。因此,现在您已经了解了如何在脚本解释器之间切换。

It just specifies what interpreter you want to use. To understand this, create a file through terminal by doing touch test.py, then type into that file the following:

#!/usr/bin/env python3
print "test"

and do chmod +x test.py to make your script executable. After this when you do ./test.py you should get an error saying:

  File "./test.py", line 2
    print "test"
               ^
SyntaxError: Missing parentheses in call to 'print'

because python3 doesn’t supprt the print operator.

Now go ahead and change the first line of your code to:

#!/usr/bin/env python2

and it’ll work, printing test to stdout, because python2 supports the print operator. So, now you’ve learned how to switch between script interpreters.


回答 13

在我看来,如果没有该行,文件运行相同。

如果是这样,那么也许您正在Windows上运行Python程序?Windows不使用该行,而是使用文件扩展名来运行与文件扩展名关联的程序。

但是在2011年,开发了“ Python启动器”,在某种程度上模仿了Windows的Linux行为。仅限于选择运行哪个Python解释器-例如,在同时安装了Python 2和Python 3的系统上进行选择。启动器可以选择py.exe通过Python安装进行安装,并且可以与.py文件关联,以便启动器将检查该行,然后启动指定的Python解释器版本。

It seems to me like the files run the same without that line.

If so, then perhaps you’re running the Python program on Windows? Windows doesn’t use that line—instead, it uses the file-name extension to run the program associated with the file extension.

However in 2011, a “Python launcher” was developed which (to some degree) mimics this Linux behaviour for Windows. This is limited just to choosing which Python interpreter is run — e.g. to select between Python 2 and Python 3 on a system where both are installed. The launcher is optionally installed as py.exe by Python installation, and can be associated with .py files so that the launcher will check that line and in turn launch the specified Python interpreter version.


回答 14

这意味着更多的历史信息,而不是“真实的”答案。

请记住,在过去,您有很多像操作系统一样的unix操作系统,其设计人员都对放置内容有自己的看法,有时甚至根本不包括Python,Perl,Bash或许多其他GNU /开源内容

甚至在不同的Linux发行版中也是如此。在Linux上-FHS之前的版本[1]-您可能在/ usr / bin /或/ usr / local / bin /中有python。或者它可能尚未安装,所以您构建了自己的并将其放入〜/ bin

Solaris是我曾经从事过的最糟糕的工作,部分是从Berkeley Unix到System V的过渡。您可能会在/ usr /,/ usr / local /,/ usr / ucb,/ opt /等目录中找到内容。对于一些真的长的路。我对Sunfreeware.com中的内容有记忆,但每个软件包都安装在其自己的目录中,但是我记不起来是否将二进制文件链接到/ usr / bin。

哦,有时/ usr / bin在NFS服务器上[2]。

因此,env开发实用程序来解决此问题。

然后,你可以写#!/bin/env interpreter只要路径是正确的事情有一个合理的运行的机会。当然,合理的意思是(对于Python和Perl)您还设置了适当的环境变量。对于bash / ksh / zsh来说,它才有效。

这很重要,因为人们正在传递shell脚本(例如perl和python),并且如果您在Red Hat Linux工作站上对/ usr / bin / python进行硬编码,那么在SGI上会很糟糕…嗯,不,我认为IRIX将python放在了正确的位置。但是在Sparc工作站上,它可能根本不运行。

我想念我的sparc站。但不是很多。好的,现在您已经让我在E-Bay上四处走动。卑鄙的人

[1]文件系统层次结构标准。https://zh.wikipedia.org/wiki/Filesystem_Hierarchy_Standard

[2]是的,有时人们仍然会做类似的事情。不,我没有在皮带上戴萝卜或洋葱。

This is meant as more of historical information than a “real” answer.

Remember that back in the day you had LOTS of unix like operating systems whose designers all had their own notion of where to put stuff, and sometimes didn’t include Python, Perl, Bash, or lots of other GNU/Open Source stuff at all.

This was even true of different Linux distributions. On Linux–pre-FHS[1]-you might have python in /usr/bin/ or /usr/local/bin/. Or it might not have been installed, so you built your own and put it in ~/bin

Solaris was the worst I ever worked on, partially as the transition from Berkeley Unix to System V. You could wind up with stuff in /usr/, /usr/local/, /usr/ucb, /opt/ etc. This could make for some really long paths. I have memories of the stuff from Sunfreeware.com installing each package in it’s own directory, but I can’t recall if it symlinked the binaries into /usr/bin or not.

Oh, and sometimes /usr/bin was on an NFS server[2].

So the env utility was developed to work around this.

Then you could write #!/bin/env interpreter and as long as the path was proper things had a reasonable chance of running. Of course, reasonable meant (for Python and Perl) that you had also set the appropriate environmental variables. For bash/ksh/zsh it just worked.

This was important because people were passing around shell scripts (like perl and python) and if you’d hard coded /usr/bin/python on your Red Hat Linux workstation it was going to break bad on a SGI…well, no, I think IRIX put python in the right spot. But on a Sparc station it might not run at all.

I miss my sparc station. But not a lot. Ok, now you’ve got me trolling around on E-Bay. Bastages.

[1] File-system Hierarchy Standard. https://en.wikipedia.org/wiki/Filesystem_Hierarchy_Standard

[2] Yes, and sometimes people still do stuff like that. And no, I did not wear either a turnip OR an onion on my belt.


回答 15

如果您是在虚拟环境中运行脚本,请说venv,然后在执行which python时执行venv将显示Python解释器的路径:

~/Envs/venv/bin/python

请注意,虚拟环境名称嵌入在Python解释器的路径中。因此,在脚本中对此路径进行硬编码将导致两个问题:

  • 如果将脚本上载到存储库,则将强制其他用户使用相同的虚拟环境名称。这是他们首先发现问题的方法。
  • 将无法运行在多个虚拟环境中的脚本,即使你有在其他虚拟环境中所有需要的软件包。

因此,要补充Jonathan的答案,理想的shebang是#!/usr/bin/env python,不仅是跨OS的可移植性,而且是跨虚拟环境的可移植性!

If you’re running your script in a virtual environment, say venv, then executing which python while working on venv will display the path to the Python interpreter:

~/Envs/venv/bin/python

Note that the name of the virtual environment is embedded in the path to the Python interpreter. Therefore, hardcoding this path in your script will cause two problems:

  • If you upload the script to a repository, you’re forcing other users to have the same virtual environment name. This is if they identify the problem first.
  • You won’t be able to run the script across multiple virtual environments even if you had all required packages in other virtual environments.

Therefore, to add to Jonathan‘s answer, the ideal shebang is #!/usr/bin/env python, not just for portability across OSes but for portability across virtual environments as well!


回答 16

考虑到python2和之间的可移植性问题python3,除非您的程序与两者兼容,否则应始终指定任何一个版本。

一些分布航运python符号链接到python3现在一段时间-不要依赖pythonpython2

PEP 394强调了这一点:

为了容忍平台之间的差异,所有需要调用Python解释器的新代码都不应指定python,而应指定python2或python3(或更具体的python2.x和python3.x版本;请参阅迁移说明) 。从shell脚本调用时,通过system()调用调用时或在任何其他上下文中调用时,都应在shebang中进行区分。

Considering the portability issues between python2 and python3, you should always specify either version unless your program is compatible with both.

Some distributions are shipping python symlinked to python3 for a while now – do not rely on python being python2.

This is emphasized by PEP 394:

In order to tolerate differences across platforms, all new code that needs to invoke the Python interpreter should not specify python, but rather should specify either python2 or python3 (or the more specific python2.x and python3.x versions; see the Migration Notes). This distinction should be made in shebangs, when invoking from a shell script, when invoking via the system() call, or when invoking in any other context.


回答 17

当您有多个python版本时,它会告诉解释器与哪个版本的python一起运行程序。

It tells the interpreter which version of python to run the program with when you have multiple versions of python.


回答 18

它允许您选择要使用的可执行文件。如果您可能安装了多个python,并且每个安装中都有不同的模块并希望选择,则这非常方便。例如

#!/bin/sh
#
# Choose the python we need. Explanation:
# a) '''\' translates to \ in shell, and starts a python multi-line string
# b) "" strings are treated as string concat by python, shell ignores them
# c) "true" command ignores its arguments
# c) exit before the ending ''' so the shell reads no further
# d) reset set docstrings to ignore the multiline comment code
#
"true" '''\'
PREFERRED_PYTHON=/Library/Frameworks/Python.framework/Versions/2.7/bin/python
ALTERNATIVE_PYTHON=/Library/Frameworks/Python.framework/Versions/3.6/bin/python3
FALLBACK_PYTHON=python3

if [ -x $PREFERRED_PYTHON ]; then
    echo Using preferred python $ALTERNATIVE_PYTHON
    exec $PREFERRED_PYTHON "$0" "$@"
elif [ -x $ALTERNATIVE_PYTHON ]; then
    echo Using alternative python $ALTERNATIVE_PYTHON
    exec $ALTERNATIVE_PYTHON "$0" "$@"
else
    echo Using fallback python $FALLBACK_PYTHON
    exec python3 "$0" "$@"
fi
exit 127
'''

__doc__ = """What this file does"""
print(__doc__)
import platform
print(platform.python_version())

It allows you to select the executable that you wish to use; which is very handy if perhaps you have multiple python installs, and different modules in each and wish to choose. e.g.

#!/bin/sh
#
# Choose the python we need. Explanation:
# a) '''\' translates to \ in shell, and starts a python multi-line string
# b) "" strings are treated as string concat by python, shell ignores them
# c) "true" command ignores its arguments
# c) exit before the ending ''' so the shell reads no further
# d) reset set docstrings to ignore the multiline comment code
#
"true" '''\'
PREFERRED_PYTHON=/Library/Frameworks/Python.framework/Versions/2.7/bin/python
ALTERNATIVE_PYTHON=/Library/Frameworks/Python.framework/Versions/3.6/bin/python3
FALLBACK_PYTHON=python3

if [ -x $PREFERRED_PYTHON ]; then
    echo Using preferred python $ALTERNATIVE_PYTHON
    exec $PREFERRED_PYTHON "$0" "$@"
elif [ -x $ALTERNATIVE_PYTHON ]; then
    echo Using alternative python $ALTERNATIVE_PYTHON
    exec $ALTERNATIVE_PYTHON "$0" "$@"
else
    echo Using fallback python $FALLBACK_PYTHON
    exec python3 "$0" "$@"
fi
exit 127
'''

__doc__ = """What this file does"""
print(__doc__)
import platform
print(platform.python_version())

回答 19

这告诉脚本python目录在哪里!

#! /usr/bin/env python

this tells the script where is python directory !

#! /usr/bin/env python

从Python调用外部命令

问题:从Python调用外部命令

您如何在Python脚本中调用外部命令(就像我在Unix Shell或Windows命令提示符下键入的一样)?

How do you call an external command (as if I’d typed it at the Unix shell or Windows command prompt) from within a Python script?


回答 0

查看标准库中的子流程模块:

import subprocess
subprocess.run(["ls", "-l"])

的优势subprocess主场迎战system的是,它是更灵活(你可以得到的stdoutstderr,“真正”的状态代码,更好的错误处理,等等)。

官方文件建议subprocess在替代模块os.system()

subprocess模块提供了更强大的功能来生成新流程并检索其结果。使用该模块优于使用此功能[ os.system()]。

与子模块更换旧的功能中部分subprocess文件可能有一些有益的食谱。

对于3.5之前的Python版本,请使用call

import subprocess
subprocess.call(["ls", "-l"])

Look at the subprocess module in the standard library:

import subprocess
subprocess.run(["ls", "-l"])

The advantage of subprocess vs. system is that it is more flexible (you can get the stdout, stderr, the “real” status code, better error handling, etc…).

The official documentation recommends the subprocess module over the alternative os.system():

The subprocess module provides more powerful facilities for spawning new processes and retrieving their results; using that module is preferable to using this function [os.system()].

The Replacing Older Functions with the subprocess Module section in the subprocess documentation may have some helpful recipes.

For versions of Python before 3.5, use call:

import subprocess
subprocess.call(["ls", "-l"])

回答 1

下面总结了调用外部程序的方法以及每种方法的优缺点:

  1. os.system("some_command with args")将命令和参数传递到系统的外壳程序。很好,因为您实际上可以以这种方式一次运行多个命令,并设置管道和输入/输出重定向。例如:

    os.system("some_command < input_file | another_command > output_file")  

但是,尽管这样做很方便,但您必须手动处理转义字符(例如空格等)的外壳字符。另一方面,这也使您可以运行仅是外壳程序命令而非实际上是外部程序的命令。请参阅文档

  1. stream = os.popen("some_command with args")os.system除了会为您提供类似于文件的对象之外,您可以使用该对象来访问该过程的标准输入/输出,它的作用与之相同。Popen还有其他3种变体,它们对I / O的处理略有不同。如果您将所有内容都作为字符串传递,那么您的命令将传递到外壳程序;如果将它们作为列表传递,则无需担心转义任何内容。请参阅文档

  2. 模块的Popensubprocess。它旨在替代它,os.popen但缺点是由于太全面而使它稍微复杂一些。例如,您会说:

    print subprocess.Popen("echo Hello World", shell=True, stdout=subprocess.PIPE).stdout.read()

    代替:

    print os.popen("echo Hello World").read()

    但是将所有选项都放在一个统一的类中而不是4个不同的popen函数是一件好事。请参阅文档

  3. call来自subprocess模块的功能。基本上就像Popen类一样,并接受所有相同的参数,但是它只是等待命令完成并提供返回代码。例如:

    return_code = subprocess.call("echo Hello World", shell=True)  

    请参阅文档

  4. 如果您使用的是Python 3.5或更高版本,则可以使用新subprocess.run函数,该函数与上面的代码非常相似,但是更加灵活,并CompletedProcess在命令完成执行后返回一个对象。

  5. os模块还具有您在C程序中拥有的所有fork / exec / spawn函数,但是我不建议直接使用它们。

subprocess模块可能是您所使用的模块。

最后,请注意,对于所有方法,在这些方法中,您将要由外壳执行的最终命令作为字符串传递给您,并且您有责任对其进行转义。如果您传递的字符串的任何部分不能被完全信任,则将带来严重的安全隐患。例如,如果用户正在输入字符串的某些/任何部分。如果不确定,请仅将这些方法与常量一起使用。为了给您暗示的含义,请考虑以下代码:

print subprocess.Popen("echo %s " % user_input, stdout=PIPE).stdout.read()

并想象用户输入了“我的妈妈不爱我&& rm -rf /”这可能会擦除整个文件系统的信息。

Here’s a summary of the ways to call external programs and the advantages and disadvantages of each:

  1. os.system("some_command with args") passes the command and arguments to your system’s shell. This is nice because you can actually run multiple commands at once in this manner and set up pipes and input/output redirection. For example:

    os.system("some_command < input_file | another_command > output_file")  
    

However, while this is convenient, you have to manually handle the escaping of shell characters such as spaces, etc. On the other hand, this also lets you run commands which are simply shell commands and not actually external programs. See the documentation.

  1. stream = os.popen("some_command with args") will do the same thing as os.system except that it gives you a file-like object that you can use to access standard input/output for that process. There are 3 other variants of popen that all handle the i/o slightly differently. If you pass everything as a string, then your command is passed to the shell; if you pass them as a list then you don’t need to worry about escaping anything. See the documentation.

  2. The Popen class of the subprocess module. This is intended as a replacement for os.popen but has the downside of being slightly more complicated by virtue of being so comprehensive. For example, you’d say:

    print subprocess.Popen("echo Hello World", shell=True, stdout=subprocess.PIPE).stdout.read()
    

    instead of:

    print os.popen("echo Hello World").read()
    

    but it is nice to have all of the options there in one unified class instead of 4 different popen functions. See the documentation.

  3. The call function from the subprocess module. This is basically just like the Popen class and takes all of the same arguments, but it simply waits until the command completes and gives you the return code. For example:

    return_code = subprocess.call("echo Hello World", shell=True)  
    

    See the documentation.

  4. If you’re on Python 3.5 or later, you can use the new subprocess.run function, which is a lot like the above but even more flexible and returns a CompletedProcess object when the command finishes executing.

  5. The os module also has all of the fork/exec/spawn functions that you’d have in a C program, but I don’t recommend using them directly.

The subprocess module should probably be what you use.

Finally please be aware that for all methods where you pass the final command to be executed by the shell as a string and you are responsible for escaping it. There are serious security implications if any part of the string that you pass can not be fully trusted. For example, if a user is entering some/any part of the string. If you are unsure, only use these methods with constants. To give you a hint of the implications consider this code:

print subprocess.Popen("echo %s " % user_input, stdout=PIPE).stdout.read()

and imagine that the user enters something “my mama didnt love me && rm -rf /” which could erase the whole filesystem.


回答 2

典型的实现:

import subprocess

p = subprocess.Popen('ls', shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
for line in p.stdout.readlines():
    print line,
retval = p.wait()

您可以随意使用stdout管道中的数据进行所需的操作。实际上,您可以简单地省略这些参数(stdout=stderr=),其行为类似于os.system()

Typical implementation:

import subprocess

p = subprocess.Popen('ls', shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
for line in p.stdout.readlines():
    print line,
retval = p.wait()

You are free to do what you want with the stdout data in the pipe. In fact, you can simply omit those parameters (stdout= and stderr=) and it’ll behave like os.system().


回答 3

关于从调用者中分离子进程的一些提示(在后台启动子进程)。

假设您要从CGI脚本开始一个长任务。也就是说,子进程的生存期应比CGI脚本执行进程的生存期长。

子流程模块文档中的经典示例是:

import subprocess
import sys

# Some code here

pid = subprocess.Popen([sys.executable, "longtask.py"]) # Call subprocess

# Some more code here

这里的想法是,您不想在long任务.py完成之前在“调用子进程”行中等待。但是尚不清楚示例中“这里有更多代码”行之后会发生什么。

我的目标平台是FreeBSD,但是开发是在Windows上进行的,因此我首先在Windows上遇到了问题。

在Windows(Windows XP)上,直到longtask.py完成工作后,父进程才会完成。这不是CGI脚本中想要的。这个问题不是特定于Python的。在PHP社区中,问题是相同的。

解决方案是将DETACHED_PROCESS 进程创建标志传递给Windows API中的基础CreateProcess函数。如果碰巧安装了pywin32,则可以从win32process模块​​中导入该标志,否则您应该自己定义它:

DETACHED_PROCESS = 0x00000008

pid = subprocess.Popen([sys.executable, "longtask.py"],
                       creationflags=DETACHED_PROCESS).pid

/ * UPD 2015.10.27 @eryksun在下面的注释中指出,语义正确的标志是CREATE_NEW_CONSOLE(0x00000010)* /

在FreeBSD上,我们还有另一个问题:父进程完成后,它也会完成子进程。那也不是您在CGI脚本中想要的。一些实验表明,问题似乎出在共享sys.stdout。可行的解决方案如下:

pid = subprocess.Popen([sys.executable, "longtask.py"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)

我没有检查其他平台上的代码,也不知道FreeBSD上该行为的原因。如果有人知道,请分享您的想法。谷歌搜索在Python中启动后台进程尚未阐明。

Some hints on detaching the child process from the calling one (starting the child process in background).

Suppose you want to start a long task from a CGI script. That is, the child process should live longer than the CGI script execution process.

The classical example from the subprocess module documentation is:

import subprocess
import sys

# Some code here

pid = subprocess.Popen([sys.executable, "longtask.py"]) # Call subprocess

# Some more code here

The idea here is that you do not want to wait in the line ‘call subprocess’ until the longtask.py is finished. But it is not clear what happens after the line ‘some more code here’ from the example.

My target platform was FreeBSD, but the development was on Windows, so I faced the problem on Windows first.

On Windows (Windows XP), the parent process will not finish until the longtask.py has finished its work. It is not what you want in a CGI script. The problem is not specific to Python; in the PHP community the problems are the same.

The solution is to pass DETACHED_PROCESS Process Creation Flag to the underlying CreateProcess function in Windows API. If you happen to have installed pywin32, you can import the flag from the win32process module, otherwise you should define it yourself:

DETACHED_PROCESS = 0x00000008

pid = subprocess.Popen([sys.executable, "longtask.py"],
                       creationflags=DETACHED_PROCESS).pid

/* UPD 2015.10.27 @eryksun in a comment below notes, that the semantically correct flag is CREATE_NEW_CONSOLE (0x00000010) */

On FreeBSD we have another problem: when the parent process is finished, it finishes the child processes as well. And that is not what you want in a CGI script either. Some experiments showed that the problem seemed to be in sharing sys.stdout. And the working solution was the following:

pid = subprocess.Popen([sys.executable, "longtask.py"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)

I have not checked the code on other platforms and do not know the reasons of the behaviour on FreeBSD. If anyone knows, please share your ideas. Googling on starting background processes in Python does not shed any light yet.


回答 4

import os
os.system("your command")

请注意,这很危险,因为未清除命令。我留给你去谷歌搜索有关“操作系统”和“系统”模块的相关文档。有很多函数(exec *和spawn *)将执行类似的操作。

import os
os.system("your command")

Note that this is dangerous, since the command isn’t cleaned. I leave it up to you to google for the relevant documentation on the ‘os’ and ‘sys’ modules. There are a bunch of functions (exec* and spawn*) that will do similar things.


回答 5

我建议你使用模块,而不是使用os.system因为它没有外壳逃避你,因此更加安全。

subprocess.call(['ping', 'localhost'])

I’d recommend using the subprocess module instead of os.system because it does shell escaping for you and is therefore much safer.

subprocess.call(['ping', 'localhost'])

回答 6

import os
cmd = 'ls -al'
os.system(cmd)

如果要返回命令的结果,可以使用os.popen。但是,自2.6版以来,不推荐使用此方法,而支持subprocess模块,其他答案已经很好地涵盖了这一点。

import os
cmd = 'ls -al'
os.system(cmd)

If you want to return the results of the command, you can use os.popen. However, this is deprecated since version 2.6 in favor of the subprocess module, which other answers have covered well.


回答 7

有很多不同的库,可让您使用Python调用外部命令。对于每个库,我都进行了描述并显示了调用外部命令的示例。我用作示例的命令是ls -l(列出所有文件)。如果您想了解有关任何库的更多信息,我已列出并链接了每个库的文档。

资料来源:

这些都是库:

希望这可以帮助您决定使用哪个库:)

子过程

子进程允许您调用外部命令,并将其连接到它们的输入/输出/错误管道(stdin,stdout和stderr)。子进程是运行命令的默认选择,但有时其他模块更好。

subprocess.run(["ls", "-l"]) # Run command
subprocess.run(["ls", "-l"], stdout=subprocess.PIPE) # This will run the command and return any output
subprocess.run(shlex.split("ls -l")) # You can also use the shlex library to split the command

操作系统

os用于“取决于操作系统的功能”。它也可以用于通过os.system和调用外部命令os.popen(注意:还有一个subprocess.popen)。os将始终运行该shell,对于不需要或不知道如何使用的人来说,它是一个简单的选择subprocess.run

os.system("ls -l") # run command
os.popen("ls -l").read() # This will run the command and return any output

SH

sh是一个子进程接口,可让您像调用程序一样调用程序。如果要多次运行命令,这很有用。

sh.ls("-l") # Run command normally
ls_cmd = sh.Command("ls") # Save command as a variable
ls_cmd() # Run command as if it were a function

plumbum是用于“类似脚本”的Python程序的库。您可以像中的函数那样调用程序sh。如果您要在没有外壳的情况下运行管道,则Plumbum很有用。

ls_cmd = plumbum.local("ls -l") # get command
ls_cmd() # run command

期待

pexpect使您可以生成子应用程序,对其进行控制并在其输出中找到模式。对于在Unix上需要tty的命令,这是子过程的更好选择。

pexpect.run("ls -l") # Run command as normal
child = pexpect.spawn('scp foo user@example.com:.') # Spawns child application
child.expect('Password:') # When this is the output
child.sendline('mypassword')

fabric是一个Python 2.5和2.7库。它允许您执行本地和远程Shell命令。Fabric是在安全Shell(SSH)中运行命令的简单替代方案

fabric.operations.local('ls -l') # Run command as normal
fabric.operations.local('ls -l', capture = True) # Run command and receive output

使者

特使被称为“人类子过程”。它用作subprocess模块周围的便利包装。

r = envoy.run("ls -l") # Run command
r.std_out # get output

命令

commands包含的包装函数os.popen,但由于subprocess是更好的选择,它已从Python 3中删除。

该编辑基于JF Sebastian的评论。

There are lots of different libraries which allow you to call external commands with Python. For each library I’ve given a description and shown an example of calling an external command. The command I used as the example is ls -l (list all files). If you want to find out more about any of the libraries I’ve listed and linked the documentation for each of them.

Sources:

These are all the libraries:

Hopefully this will help you make a decision on which library to use :)

subprocess

Subprocess allows you to call external commands and connect them to their input/output/error pipes (stdin, stdout, and stderr). Subprocess is the default choice for running commands, but sometimes other modules are better.

subprocess.run(["ls", "-l"]) # Run command
subprocess.run(["ls", "-l"], stdout=subprocess.PIPE) # This will run the command and return any output
subprocess.run(shlex.split("ls -l")) # You can also use the shlex library to split the command

os

os is used for “operating system dependent functionality”. It can also be used to call external commands with os.system and os.popen (Note: There is also a subprocess.popen). os will always run the shell and is a simple alternative for people who don’t need to, or don’t know how to use subprocess.run.

os.system("ls -l") # run command
os.popen("ls -l").read() # This will run the command and return any output

sh

sh is a subprocess interface which lets you call programs as if they were functions. This is useful if you want to run a command multiple times.

sh.ls("-l") # Run command normally
ls_cmd = sh.Command("ls") # Save command as a variable
ls_cmd() # Run command as if it were a function

plumbum

plumbum is a library for “script-like” Python programs. You can call programs like functions as in sh. Plumbum is useful if you want to run a pipeline without the shell.

ls_cmd = plumbum.local("ls -l") # get command
ls_cmd() # run command

pexpect

pexpect lets you spawn child applications, control them and find patterns in their output. This is a better alternative to subprocess for commands that expect a tty on Unix.

pexpect.run("ls -l") # Run command as normal
child = pexpect.spawn('scp foo user@example.com:.') # Spawns child application
child.expect('Password:') # When this is the output
child.sendline('mypassword')

fabric

fabric is a Python 2.5 and 2.7 library. It allows you to execute local and remote shell commands. Fabric is simple alternative for running commands in a secure shell (SSH)

fabric.operations.local('ls -l') # Run command as normal
fabric.operations.local('ls -l', capture = True) # Run command and receive output

envoy

envoy is known as “subprocess for humans”. It is used as a convenience wrapper around the subprocess module.

r = envoy.run("ls -l") # Run command
r.std_out # get output

commands

commands contains wrapper functions for os.popen, but it has been removed from Python 3 since subprocess is a better alternative.

The edit was based on J.F. Sebastian’s comment.


回答 8

我总是用fabric这样的东西:

from fabric.operations import local
result = local('ls', capture=True)
print "Content:/n%s" % (result, )

但这似乎是一个很好的工具:sh(Python子进程接口)

看一个例子:

from sh import vgdisplay
print vgdisplay()
print vgdisplay('-v')
print vgdisplay(v=True)

I always use fabric for this things like:

from fabric.operations import local
result = local('ls', capture=True)
print "Content:/n%s" % (result, )

But this seem to be a good tool: sh (Python subprocess interface).

Look at an example:

from sh import vgdisplay
print vgdisplay()
print vgdisplay('-v')
print vgdisplay(v=True)

回答 9

还要检查“ pexpect” Python库。

它允许交互式控制外部程序/命令,甚至包括ssh,ftp,telnet等。您可以键入以下内容:

child = pexpect.spawn('ftp 192.168.0.24')

child.expect('(?i)name .*: ')

child.sendline('anonymous')

child.expect('(?i)password')

Check the “pexpect” Python library, too.

It allows for interactive controlling of external programs/commands, even ssh, ftp, telnet, etc. You can just type something like:

child = pexpect.spawn('ftp 192.168.0.24')

child.expect('(?i)name .*: ')

child.sendline('anonymous')

child.expect('(?i)password')

回答 10

与标准库

使用子流程模块(Python 3):

import subprocess
subprocess.run(['ls', '-l'])

这是推荐的标准方式。但是,构造和编写更复杂的任务(管道,输出,输入等)可能很繁琐。

关于Python版本的注意事项:如果您仍在使用Python 2,subprocess.call的工作方式与此类似。

ProTip:shlex.split可以帮助您解析,和其他功能的命令run,以防您不想(或您不能!)以列表形式提供它们:callsubprocess

import shlex
import subprocess
subprocess.run(shlex.split('ls -l'))

具有外部依赖性

如果您不介意外部依赖性,请使用plumbum

from plumbum.cmd import ifconfig
print(ifconfig['wlan0']())

这是最好的subprocess包装纸。它是跨平台的,即可以在Windows和类似Unix的系统上运行。由安装pip install plumbum

另一个受欢迎的图书馆是sh

from sh import ifconfig
print(ifconfig('wlan0'))

但是,已sh放弃Windows支持,因此它不像以前那样出色。由安装pip install sh

With the standard library

Use the subprocess module (Python 3):

import subprocess
subprocess.run(['ls', '-l'])

It is the recommended standard way. However, more complicated tasks (pipes, output, input, etc.) can be tedious to construct and write.

Note on Python version: If you are still using Python 2, subprocess.call works in a similar way.

ProTip: shlex.split can help you to parse the command for run, call, and other subprocess functions in case you don’t want (or you can’t!) provide them in form of lists:

import shlex
import subprocess
subprocess.run(shlex.split('ls -l'))

With external dependencies

If you do not mind external dependencies, use plumbum:

from plumbum.cmd import ifconfig
print(ifconfig['wlan0']())

It is the best subprocess wrapper. It’s cross-platform, i.e. it works on both Windows and Unix-like systems. Install by pip install plumbum.

Another popular library is sh:

from sh import ifconfig
print(ifconfig('wlan0'))

However, sh dropped Windows support, so it’s not as awesome as it used to be. Install by pip install sh.


回答 11

如果您需要从您所呼叫的命令的输出,那么你可以使用subprocess.check_output(Python的2.7+)。

>>> subprocess.check_output(["ls", "-l", "/dev/null"])
'crw-rw-rw- 1 root root 1, 3 Oct 18  2007 /dev/null\n'

还要注意shell参数。

如果shell是True,则将通过Shell执行指定的命令。如果您主要将Python用于大多数系统外壳程序提供的增强控制流,并且仍希望方便地访问其他外壳程序功能(例如外壳程序管道,文件名通配符,环境变量扩展以及〜扩展到用户的家),则这可能很有用。目录。但是请注意,Python本身提供的实现多壳状的功能(尤其是globfnmatchos.walk()os.path.expandvars()os.path.expanduser(),和shutil)。

If you need the output from the command you are calling, then you can use subprocess.check_output (Python 2.7+).

>>> subprocess.check_output(["ls", "-l", "/dev/null"])
'crw-rw-rw- 1 root root 1, 3 Oct 18  2007 /dev/null\n'

Also note the shell parameter.

If shell is True, the specified command will be executed through the shell. This can be useful if you are using Python primarily for the enhanced control flow it offers over most system shells and still want convenient access to other shell features such as shell pipes, filename wildcards, environment variable expansion, and expansion of ~ to a user’s home directory. However, note that Python itself offers implementations of many shell-like features (in particular, glob, fnmatch, os.walk(), os.path.expandvars(), os.path.expanduser(), and shutil).


回答 12

这就是我运行命令的方式。这段代码包含了您非常需要的所有内容

from subprocess import Popen, PIPE
cmd = "ls -l ~/"
p = Popen(cmd , shell=True, stdout=PIPE, stderr=PIPE)
out, err = p.communicate()
print "Return code: ", p.returncode
print out.rstrip(), err.rstrip()

This is how I run my commands. This code has everything you need pretty much

from subprocess import Popen, PIPE
cmd = "ls -l ~/"
p = Popen(cmd , shell=True, stdout=PIPE, stderr=PIPE)
out, err = p.communicate()
print "Return code: ", p.returncode
print out.rstrip(), err.rstrip()

回答 13

更新:

subprocess.run如果您的代码不需要保持与早期Python版本的兼容性,则从python 3.5开始,建议使用此方法。它更加一致,并且提供与Envoy类似的易用性。(管道并不是那么简单。有关如何查看此问题的信息。)

以下是文档中的一些示例。

运行一个过程:

>>> subprocess.run(["ls", "-l"])  # Doesn't capture output
CompletedProcess(args=['ls', '-l'], returncode=0)

在失败的跑步上加薪:

>>> subprocess.run("exit 1", shell=True, check=True)
Traceback (most recent call last):
  ...
subprocess.CalledProcessError: Command 'exit 1' returned non-zero exit status 1

捕获输出:

>>> subprocess.run(["ls", "-l", "/dev/null"], stdout=subprocess.PIPE)
CompletedProcess(args=['ls', '-l', '/dev/null'], returncode=0,
stdout=b'crw-rw-rw- 1 root root 1, 3 Jan 23 16:23 /dev/null\n')

原始答案:

我建议尝试Envoy。它是子流程的包装,后者旨在替换较旧的模块和功能。特使是人类的子过程。

自述文件中的示例用法:

>>> r = envoy.run('git config', data='data to pipe in', timeout=2)

>>> r.status_code
129
>>> r.std_out
'usage: git config [options]'
>>> r.std_err
''

管道周围的东西:

>>> r = envoy.run('uptime | pbcopy')

>>> r.command
'pbcopy'
>>> r.status_code
0

>>> r.history
[<Response 'uptime'>]

Update:

subprocess.run is the recommended approach as of Python 3.5 if your code does not need to maintain compatibility with earlier Python versions. It’s more consistent and offers similar ease-of-use as Envoy. (Piping isn’t as straightforward though. See this question for how.)

Here’s some examples from the documentation.

Run a process:

>>> subprocess.run(["ls", "-l"])  # Doesn't capture output
CompletedProcess(args=['ls', '-l'], returncode=0)

Raise on failed run:

>>> subprocess.run("exit 1", shell=True, check=True)
Traceback (most recent call last):
  ...
subprocess.CalledProcessError: Command 'exit 1' returned non-zero exit status 1

Capture output:

>>> subprocess.run(["ls", "-l", "/dev/null"], stdout=subprocess.PIPE)
CompletedProcess(args=['ls', '-l', '/dev/null'], returncode=0,
stdout=b'crw-rw-rw- 1 root root 1, 3 Jan 23 16:23 /dev/null\n')

Original answer:

I recommend trying Envoy. It’s a wrapper for subprocess, which in turn aims to replace the older modules and functions. Envoy is subprocess for humans.

Example usage from the README:

>>> r = envoy.run('git config', data='data to pipe in', timeout=2)

>>> r.status_code
129
>>> r.std_out
'usage: git config [options]'
>>> r.std_err
''

Pipe stuff around too:

>>> r = envoy.run('uptime | pbcopy')

>>> r.command
'pbcopy'
>>> r.status_code
0

>>> r.history
[<Response 'uptime'>]

回答 14

使用子过程

…或一个非常简单的命令:

import os
os.system('cat testfile')

Use subprocess.

…or for a very simple command:

import os
os.system('cat testfile')

回答 15

在Python中调用外部命令

简单,使用subprocess.run,它返回一个CompletedProcess对象:

>>> import subprocess
>>> completed_process = subprocess.run('python --version')
Python 3.6.1 :: Anaconda 4.4.0 (64-bit)
>>> completed_process
CompletedProcess(args='python --version', returncode=0)

为什么?

从Python 3.5开始,文档建议使用subprocess.run

推荐的调用子流程的方法是将run()函数用于它可以处理的所有用例。对于更高级的用例,可以直接使用基础Popen接口。

这是最简单的用法示例-完全按照要求进行:

>>> import subprocess
>>> completed_process = subprocess.run('python --version')
Python 3.6.1 :: Anaconda 4.4.0 (64-bit)
>>> completed_process
CompletedProcess(args='python --version', returncode=0)

run等待命令成功完成,然后返回一个CompletedProcess对象。相反,它可以引发TimeoutExpired(如果您给它提供一个timeout=参数)或CalledProcessError(如果失败并通过check=True)。

从上面的示例可以推断,默认情况下,stdout和stderr都通过管道传递到您自己的stdout和stderr。

我们可以检查返回的对象,并查看给出的命令和返回码:

>>> completed_process.args
'python --version'
>>> completed_process.returncode
0

捕获输出

如果要捕获输出,则可以传递subprocess.PIPE给相应的stderrstdout

>>> cp = subprocess.run('python --version', 
                        stderr=subprocess.PIPE, 
                        stdout=subprocess.PIPE)
>>> cp.stderr
b'Python 3.6.1 :: Anaconda 4.4.0 (64-bit)\r\n'
>>> cp.stdout
b''

(我发现将版本信息放入stderr而不是stdout很有意思,并且有点违反直觉。)

传递命令清单

可以很容易地从手动提供命令字符串(如问题所提示)转变为以编程方式构建的字符串。不要以编程方式构建字符串。这是一个潜在的安全问题。最好假设您不信任输入。

>>> import textwrap
>>> args = ['python', textwrap.__file__]
>>> cp = subprocess.run(args, stdout=subprocess.PIPE)
>>> cp.stdout
b'Hello there.\r\n  This is indented.\r\n'

注意,仅args应按位置传递。

完整签名

这是源中的实际签名,如下所示help(run)

def run(*popenargs, input=None, timeout=None, check=False, **kwargs):

popenargskwargs被给予Popen的构造。input可以是universal_newlines=True将通过管道传输到子进程的stdin 的字节字符串(或unicode,如果指定encoding或)。

该文档描述了timeout=check=True比我更可以:

超时参数传递给Popen.communicate()。如果超时到期,子进程将被终止并等待。子进程终止后,将重新引发TimeoutExpired异常。

如果check为true,并且进程以非零退出代码退出,则将引发CalledProcessError异常。该异常的属性包含参数,退出代码以及stdout和stderr(如果已捕获)。

这个示例check=True比我能想到的更好:

>>> subprocess.run("exit 1", shell=True, check=True)
Traceback (most recent call last):
  ...
subprocess.CalledProcessError: Command 'exit 1' returned non-zero exit status 1

扩展签名

这是文档中提供的扩展签名:

subprocess.run(args, *, stdin=None, input=None, stdout=None, stderr=None, 
shell=False, cwd=None, timeout=None, check=False, encoding=None, 
errors=None)

请注意,这表明只应在位置传递args列表。因此,将其余参数作为关键字参数传递。

开普

何时使用Popen代替?我将很难仅根据参数来找到用例。Popen但是,直接使用pollwill 将使您能够访问其方法,包括,“ send_signal”,“ terminate”和“ wait”。

这是来源中Popen给出的签名。我认为这是信息的最精确封装(与相对):help(Popen)

def __init__(self, args, bufsize=-1, executable=None,
             stdin=None, stdout=None, stderr=None,
             preexec_fn=None, close_fds=_PLATFORM_DEFAULT_CLOSE_FDS,
             shell=False, cwd=None, env=None, universal_newlines=False,
             startupinfo=None, creationflags=0,
             restore_signals=True, start_new_session=False,
             pass_fds=(), *, encoding=None, errors=None):

但更多的是信息Popen文档

subprocess.Popen(args, bufsize=-1, executable=None, stdin=None,
                 stdout=None, stderr=None, preexec_fn=None, close_fds=True,
                 shell=False, cwd=None, env=None, universal_newlines=False,
                 startupinfo=None, creationflags=0, restore_signals=True,
                 start_new_session=False, pass_fds=(), *, encoding=None, errors=None)

在新进程中执行子程序。在POSIX上,该类使用类似于os.execvp()的行为来执行子程序。在Windows上,该类使用Windows CreateProcess()函数。Popen的参数如下。

剩下的内容Popen将作为读者的练习。

Calling an external command in Python

Simple, use subprocess.run, which returns a CompletedProcess object:

>>> import subprocess
>>> completed_process = subprocess.run('python --version')
Python 3.6.1 :: Anaconda 4.4.0 (64-bit)
>>> completed_process
CompletedProcess(args='python --version', returncode=0)

Why?

As of Python 3.5, the documentation recommends subprocess.run:

The recommended approach to invoking subprocesses is to use the run() function for all use cases it can handle. For more advanced use cases, the underlying Popen interface can be used directly.

Here’s an example of the simplest possible usage – and it does exactly as asked:

>>> import subprocess
>>> completed_process = subprocess.run('python --version')
Python 3.6.1 :: Anaconda 4.4.0 (64-bit)
>>> completed_process
CompletedProcess(args='python --version', returncode=0)

run waits for the command to successfully finish, then returns a CompletedProcess object. It may instead raise TimeoutExpired (if you give it a timeout= argument) or CalledProcessError (if it fails and you pass check=True).

As you might infer from the above example, stdout and stderr both get piped to your own stdout and stderr by default.

We can inspect the returned object and see the command that was given and the returncode:

>>> completed_process.args
'python --version'
>>> completed_process.returncode
0

Capturing output

If you want to capture the output, you can pass subprocess.PIPE to the appropriate stderr or stdout:

>>> cp = subprocess.run('python --version', 
                        stderr=subprocess.PIPE, 
                        stdout=subprocess.PIPE)
>>> cp.stderr
b'Python 3.6.1 :: Anaconda 4.4.0 (64-bit)\r\n'
>>> cp.stdout
b''

(I find it interesting and slightly counterintuitive that the version info gets put to stderr instead of stdout.)

Pass a command list

One might easily move from manually providing a command string (like the question suggests) to providing a string built programmatically. Don’t build strings programmatically. This is a potential security issue. It’s better to assume you don’t trust the input.

>>> import textwrap
>>> args = ['python', textwrap.__file__]
>>> cp = subprocess.run(args, stdout=subprocess.PIPE)
>>> cp.stdout
b'Hello there.\r\n  This is indented.\r\n'

Note, only args should be passed positionally.

Full Signature

Here’s the actual signature in the source and as shown by help(run):

def run(*popenargs, input=None, timeout=None, check=False, **kwargs):

The popenargs and kwargs are given to the Popen constructor. input can be a string of bytes (or unicode, if specify encoding or universal_newlines=True) that will be piped to the subprocess’s stdin.

The documentation describes timeout= and check=True better than I could:

The timeout argument is passed to Popen.communicate(). If the timeout expires, the child process will be killed and waited for. The TimeoutExpired exception will be re-raised after the child process has terminated.

If check is true, and the process exits with a non-zero exit code, a CalledProcessError exception will be raised. Attributes of that exception hold the arguments, the exit code, and stdout and stderr if they were captured.

and this example for check=True is better than one I could come up with:

>>> subprocess.run("exit 1", shell=True, check=True)
Traceback (most recent call last):
  ...
subprocess.CalledProcessError: Command 'exit 1' returned non-zero exit status 1

Expanded Signature

Here’s an expanded signature, as given in the documentation:

subprocess.run(args, *, stdin=None, input=None, stdout=None, stderr=None, 
shell=False, cwd=None, timeout=None, check=False, encoding=None, 
errors=None)

Note that this indicates that only the args list should be passed positionally. So pass the remaining arguments as keyword arguments.

Popen

When use Popen instead? I would struggle to find use-case based on the arguments alone. Direct usage of Popen would, however, give you access to its methods, including poll, ‘send_signal’, ‘terminate’, and ‘wait’.

Here’s the Popen signature as given in the source. I think this is the most precise encapsulation of the information (as opposed to help(Popen)):

def __init__(self, args, bufsize=-1, executable=None,
             stdin=None, stdout=None, stderr=None,
             preexec_fn=None, close_fds=_PLATFORM_DEFAULT_CLOSE_FDS,
             shell=False, cwd=None, env=None, universal_newlines=False,
             startupinfo=None, creationflags=0,
             restore_signals=True, start_new_session=False,
             pass_fds=(), *, encoding=None, errors=None):

But more informative is the Popen documentation:

subprocess.Popen(args, bufsize=-1, executable=None, stdin=None,
                 stdout=None, stderr=None, preexec_fn=None, close_fds=True,
                 shell=False, cwd=None, env=None, universal_newlines=False,
                 startupinfo=None, creationflags=0, restore_signals=True,
                 start_new_session=False, pass_fds=(), *, encoding=None, errors=None)

Execute a child program in a new process. On POSIX, the class uses os.execvp()-like behavior to execute the child program. On Windows, the class uses the Windows CreateProcess() function. The arguments to Popen are as follows.

Understanding the remaining documentation on Popen will be left as an exercise for the reader.


回答 16

os.system可以,但是有点过时。这也不是很安全。相反,请尝试subprocesssubprocess不会直接调用sh,因此比os.system

在此处获取更多信息。

os.system is OK, but kind of dated. It’s also not very secure. Instead, try subprocess. subprocess does not call sh directly and is therefore more secure than os.system.

Get more information here.


回答 17

还有

>>> from plumbum import local
>>> ls = local["ls"]
>>> ls
LocalCommand(<LocalPath /bin/ls>)
>>> ls()
u'build.py\ndist\ndocs\nLICENSE\nplumbum\nREADME.rst\nsetup.py\ntests\ntodo.txt\n'
>>> notepad = local["c:\\windows\\notepad.exe"]
>>> notepad()                                   # Notepad window pops up
u''                                             # Notepad window is closed by user, command returns

There is also Plumbum

>>> from plumbum import local
>>> ls = local["ls"]
>>> ls
LocalCommand(<LocalPath /bin/ls>)
>>> ls()
u'build.py\ndist\ndocs\nLICENSE\nplumbum\nREADME.rst\nsetup.py\ntests\ntodo.txt\n'
>>> notepad = local["c:\\windows\\notepad.exe"]
>>> notepad()                                   # Notepad window pops up
u''                                             # Notepad window is closed by user, command returns

回答 18

采用:

import os

cmd = 'ls -al'

os.system(cmd)

os-此模块提供了使用依赖于操作系统的功能的可移植方式。

对于更多的os功能,这里是文档。

Use:

import os

cmd = 'ls -al'

os.system(cmd)

os – This module provides a portable way of using operating system-dependent functionality.

For the more os functions, here is the documentation.


回答 19

可能很简单:

import os
cmd = "your command"
os.system(cmd)

It can be this simple:

import os
cmd = "your command"
os.system(cmd)

回答 20

我非常喜欢shell_command的简单性。它建立在子流程模块的顶部。

这是文档中的示例:

>>> from shell_command import shell_call
>>> shell_call("ls *.py")
setup.py  shell_command.py  test_shell_command.py
0
>>> shell_call("ls -l *.py")
-rw-r--r-- 1 ncoghlan ncoghlan  391 2011-12-11 12:07 setup.py
-rw-r--r-- 1 ncoghlan ncoghlan 7855 2011-12-11 16:16 shell_command.py
-rwxr-xr-x 1 ncoghlan ncoghlan 8463 2011-12-11 16:17 test_shell_command.py
0

I quite like shell_command for its simplicity. It’s built on top of the subprocess module.

Here’s an example from the documentation:

>>> from shell_command import shell_call
>>> shell_call("ls *.py")
setup.py  shell_command.py  test_shell_command.py
0
>>> shell_call("ls -l *.py")
-rw-r--r-- 1 ncoghlan ncoghlan  391 2011-12-11 12:07 setup.py
-rw-r--r-- 1 ncoghlan ncoghlan 7855 2011-12-11 16:16 shell_command.py
-rwxr-xr-x 1 ncoghlan ncoghlan 8463 2011-12-11 16:17 test_shell_command.py
0

回答 21

这里还有另一个以前没有提到的区别。

subprocess.Popen将<command>作为子进程执行。就我而言,我需要执行文件<a>,该文件需要与另一个程序<b>通信。

我尝试了子流程,执行成功。但是<b>无法与<a>通信。当我从终端运行时,一切都正常。

还有一个:(注意:kwrite的行为与其他应用程序不同。如果在Firefox上尝试以下操作,结果将有所不同。)

如果尝试这样做os.system("kwrite"),程序流将冻结,直到用户关闭kwrite。为了克服这个问题,我改为尝试os.system(konsole -e kwrite)。这个时间程序继续进行,但是kwrite成为了控制台的子进程。

任何人都运行kwrite而不是子进程(即,它必须在系统监视器中显示在树的最左侧)。

There is another difference here which is not mentioned previously.

subprocess.Popen executes the <command> as a subprocess. In my case, I need to execute file <a> which needs to communicate with another program, <b>.

I tried subprocess, and execution was successful. However <b> could not communicate with <a>. Everything is normal when I run both from the terminal.

One more: (NOTE: kwrite behaves different from other applications. If you try the below with Firefox, the results will not be the same.)

If you try os.system("kwrite"), program flow freezes until the user closes kwrite. To overcome that I tried instead os.system(konsole -e kwrite). This time program continued to flow, but kwrite became the subprocess of the console.

Anyone runs the kwrite not being a subprocess (i.e. in the system monitor it must appear at the leftmost edge of the tree).


回答 22

os.system不允许您存储结果,因此,如果要将结果存储在某个列表或其他内容中,则subprocess.call可以使用。

os.system does not allow you to store results, so if you want to store results in some list or something, a subprocess.call works.


回答 23

subprocess.check_call如果您不想测试返回值,则非常方便。任何错误都会引发异常。

subprocess.check_call is convenient if you don’t want to test return values. It throws an exception on any error.


回答 24

我倾向于将进程shlex一起使用(以处理带引号的字符串的转义):

>>> import subprocess, shlex
>>> command = 'ls -l "/your/path/with spaces/"'
>>> call_params = shlex.split(command)
>>> print call_params
["ls", "-l", "/your/path/with spaces/"]
>>> subprocess.call(call_params)

I tend to use subprocess together with shlex (to handle escaping of quoted strings):

>>> import subprocess, shlex
>>> command = 'ls -l "/your/path/with spaces/"'
>>> call_params = shlex.split(command)
>>> print call_params
["ls", "-l", "/your/path/with spaces/"]
>>> subprocess.call(call_params)

回答 25

无耻的插件,我为此写了一个库:P https://github.com/houqp/shell.py

目前,它基本上是popen和shlex的包装。它还支持管道命令,因此您可以在Python中更轻松地链接命令。因此,您可以执行以下操作:

ex('echo hello shell.py') | "awk '{print $2}'"

Shameless plug, I wrote a library for this :P https://github.com/houqp/shell.py

It’s basically a wrapper for popen and shlex for now. It also supports piping commands so you can chain commands easier in Python. So you can do things like:

ex('echo hello shell.py') | "awk '{print $2}'"

回答 26

在Windows中你可以导入subprocess模块,并通过调用运行外部命令subprocess.Popen()subprocess.Popen().communicate()subprocess.Popen().wait()如下:

# Python script to run a command line
import subprocess

def execute(cmd):
    """
        Purpose  : To execute a command and return exit status
        Argument : cmd - command to execute
        Return   : exit_code
    """
    process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    (result, error) = process.communicate()

    rc = process.wait()

    if rc != 0:
        print "Error: failed to execute command:", cmd
        print error
    return result
# def

command = "tasklist | grep python"
print "This process detail: \n", execute(command)

输出:

This process detail:
python.exe                     604 RDP-Tcp#0                  4      5,660 K

In Windows you can just import the subprocess module and run external commands by calling subprocess.Popen(), subprocess.Popen().communicate() and subprocess.Popen().wait() as below:

# Python script to run a command line
import subprocess

def execute(cmd):
    """
        Purpose  : To execute a command and return exit status
        Argument : cmd - command to execute
        Return   : exit_code
    """
    process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    (result, error) = process.communicate()

    rc = process.wait()

    if rc != 0:
        print "Error: failed to execute command:", cmd
        print error
    return result
# def

command = "tasklist | grep python"
print "This process detail: \n", execute(command)

Output:

This process detail:
python.exe                     604 RDP-Tcp#0                  4      5,660 K

回答 27

在Linux下,如果您想调用将独立执行的外部命令(在python脚本终止后将继续运行),则可以使用简单的队列作为任务假脱机程序at命令

任务假脱机程序的示例:

import os
os.system('ts <your-command>')

有关任务后台处理程序(ts)的注意事项:

  1. 您可以使用以下命令设置要运行的并发进程数(“插槽”):

    ts -S <number-of-slots>

  2. 安装ts不需要管理员权限。您可以使用简单的源代码下载并编译它make,然后将其添加到路径中,即可完成操作。

Under Linux, in case you would like to call an external command that will execute independently (will keep running after the python script terminates), you can use a simple queue as task spooler or the at command

An example with task spooler:

import os
os.system('ts <your-command>')

Notes about task spooler (ts):

  1. You could set the number of concurrent processes to be run (“slots”) with:

    ts -S <number-of-slots>

  2. Installing ts doesn’t requires admin privileges. You can download and compile it from source with a simple make, add it to your path and you’re done.


回答 28

您可以使用Popen,然后可以检查过程的状态:

from subprocess import Popen

proc = Popen(['ls', '-l'])
if proc.poll() is None:
    proc.kill()

签出subprocess.Popen

You can use Popen, and then you can check the procedure’s status:

from subprocess import Popen

proc = Popen(['ls', '-l'])
if proc.poll() is None:
    proc.kill()

Check out subprocess.Popen.


回答 29

要从OpenStack Neutron获取网络ID :

#!/usr/bin/python
import os
netid = "nova net-list | awk '/ External / { print $2 }'"
temp = os.popen(netid).read()  /* Here temp also contains new line (\n) */
networkId = temp.rstrip()
print(networkId)

nova net-list的输出

+--------------------------------------+------------+------+
| ID                                   | Label      | CIDR |
+--------------------------------------+------------+------+
| 431c9014-5b5d-4b51-a357-66020ffbb123 | test1      | None |
| 27a74fcd-37c0-4789-9414-9531b7e3f126 | External   | None |
| 5a2712e9-70dc-4b0e-9281-17e02f4684c9 | management | None |
| 7aa697f5-0e60-4c15-b4cc-9cb659698512 | Internal   | None |
+--------------------------------------+------------+------+

打印输出(networkId)

27a74fcd-37c0-4789-9414-9531b7e3f126

To fetch the network id from the OpenStack Neutron:

#!/usr/bin/python
import os
netid = "nova net-list | awk '/ External / { print $2 }'"
temp = os.popen(netid).read()  /* Here temp also contains new line (\n) */
networkId = temp.rstrip()
print(networkId)

Output of nova net-list

+--------------------------------------+------------+------+
| ID                                   | Label      | CIDR |
+--------------------------------------+------------+------+
| 431c9014-5b5d-4b51-a357-66020ffbb123 | test1      | None |
| 27a74fcd-37c0-4789-9414-9531b7e3f126 | External   | None |
| 5a2712e9-70dc-4b0e-9281-17e02f4684c9 | management | None |
| 7aa697f5-0e60-4c15-b4cc-9cb659698512 | Internal   | None |
+--------------------------------------+------------+------+

Output of print(networkId)

27a74fcd-37c0-4789-9414-9531b7e3f126

Nerd-fonts 标志性的字体聚合器、集合和补丁程序

书呆子字体是一个用大量字形(图标)为开发人员目标字体打补丁的项目,内涵3600多个图标,50多个补丁字体:Hack,Source Code Pro,更多。字形集合:字体、材质设计图标、Octicons等。具体地说,就是从流行的“图标字体”中添加大量额外的字形,例如Font Awesome ➶Devicons ➶Octicons ➶,以及others。

重要通知

目录

TL;DR

Installation Options

Features

Developer / Contributor

Project Motivation

其他信息

TL;DR

书呆子字体采用流行的编程字体,并添加了一堆字形。还有一个font patcher如果您所需的字体尚未打补丁,则可用。有关更多高级信息,请参阅wiki如果您正在寻找Vim插件,请参阅VimDevIcons ➶

各种字体下载选项

如果你

功能

字形集

🔍🔍现在,您可以在上轻松搜索字形NerdFonts.com通过Cheat Sheet

看见Wiki: Glyph Sets and Codepoints for more details

Shell中的图标名称

看见Wiki: Icon names in shell

打补丁的字体

字体名称 字体名称和存储库 *RFN EM大小 状态
3270 Nerd Font 3270 不是的 1000个
Agave Agave 不是的 2048年
Anonymice Nerd Font Anonymous Pro 不是的 2048年
Arimo Arimo 不是的 2048年
Aurulent Sans Mono Nerd Font 不是的 1000个
BigBlueTerminal 不是的 1200
Bitstream Vera Sans Mono Nerd Font 不是的 2048年
Blex* IBM Plex Mono 1000个
Caskaydia Cove Nerd Font* Cascadia Code 2048年
Code New Roman Nerd Font 不是的 2048年
Cousine Nerd Font Cousine 不是的 1000个
DaddyTimeMono DaddyTimeMono 不是的 1024
DejaVu Sans Mono Nerd Font 不是的 2048年
Droid Sans Mono Nerd Font 不是的 2048年
Fantasque Sans Nerd Font Fantasque Sans 不是的 2048年
Fira Code Nerd Font Fira Code 不是的 1000个
Fira Mono Nerd Font Fira 不是的 1000个
Go Mono Nerd Font Go-Mono 不是的 1000个
Gohu Nerd Font Gohu TTFGohu 不是的 1000个
Hack Nerd Font Hack 不是的 2048年
Hasklug Nerd Font* Hasklig 1000个
Heavy Data Mono Nerd Font 不是的 2048年
Hurmit Nerd Font 不是的 1000个
iM-Writing* iA-Writer 1000个
Inconsolata Nerd Font 不是的 1000个
Inconsolata Go Nerd Font 不是的 1000个
Inconsolata LGC Nerd Font 不是的 1000个
Iosevka Nerd Font Iosevka 不是的 1000个 #83
JetBrains Mono JetBrains Mono 不是的 1000个
Lekton Nerd Font 不是的 1000个
Literation Mono Nerd Font* Liberation 2048年
Lilex Nerd Font Lilex 不是的 2000年
Meslo Nerd Font 不是的 2048年
Monofur Nerd Font 不是的 2400
Monoid Nerd Font 不是的 1536
Mononoki Nerd Font Mononoki 不是的 1024
M+ (MPlus) Nerd Font 不是的 1000个
Noto 不是的 1000个
OpenDyslexic 不是的 1000个
Overpass 不是的 1000个
ProFont (Windows tweaked) Nerd Font 不是的 1200
ProFont (x11) Nerd Font 不是的 1000个
ProggyClean Nerd Font 不是的 2048年 不完美
Roboto Mono 不是的 2048年
Sauce Code Nerd Font Source 1000个
Shure Tech Mono Nerd Font* Share Tech Mono 1000个
Space Mono Nerd Font Space Mono 不是的 1000个
Terminess Nerd Font* Terminus Font 1000个
Tinos 不是的 2048年
Ubuntu Nerd Font 不是的 1000个
Ubuntu Mono Nerd Font 不是的 1000个
Victor Mono Victor Mono 不是的 1000个

*RFN=保留字体名称

组合

  • 完毕1,485,000修补字体的独特变体/组合(功率集):
    • 50修补的字体字样
    • 719打补丁的字体系列
    • 2,876“完整的”变体/组合
    • '1,485,410'可能的变体/组合
      • 1,488,286计算的组合总数(2,876+1,428,110)
  • 每种字体的组合是以下字体的任意组合Variations

变体

字体安装

Option 1: Download and Install Manually

最佳选择速战速决获取特定的单个字体

下载特定的patched font随你选择

Option 2: Release Archive Download

如果您想要存档或完成字体系列变体(粗体、斜体等)

字体可以软件包的形式在latest release

Option 3: Install Script

如果您想要的话,最好的选择自动化安装或用于脚本

注意事项:仅适用于Linux和MacOS(OS X)注意事项需要克隆到目前为止的回购

所有字体:

  • 安装所有打补丁的字体(警告:这是大量的字体加起来很大)
./install.sh

单一字体:

  • 安装您选择的单一字体
./install.sh <FontName>
./install.sh Hack
./install.sh HeavyData

Option 4: Homebrew Fonts

如果启用,则为最佳选项MacOS并且想要使用自制酒

所有字体均可通过Homebrew Cask Fonts在MacOS(OS X)上

brew tap homebrew/cask-fonts
brew install --cask font-hack-nerd-font

Option 5: Clone the Repo

最佳选择完全控制最多字体,或者贡献走向发展

此存储库的克隆是如果您只对有限的一组字体感兴趣,则不需要也不高效(主要是由于存储库的大小

但是,如果您确实要克隆存储库,请确保浅层克隆:

git clone --depth 1

Option 6: Ad Hoc Curl Download

选项,如果要使用curl命令或用于脚本

Linux操作系统

mkdir -p ~/.local/share/fonts
cd ~/.local/share/fonts && curl -fLo "Droid Sans Mono for Powerline Nerd Font Complete.otf" https://github.com/ryanoasis/nerd-fonts/raw/master/patched-fonts/DroidSansMono/complete/Droid%20Sans%20Mono%20Nerd%20Font%20Complete.otf

注:不推荐使用的备用路径:~/.fonts

MacOS(OS X)

cd ~/Library/Fonts && curl -fLo "Droid Sans Mono for Powerline Nerd Font Complete.otf" https://github.com/ryanoasis/nerd-fonts/raw/master/patched-fonts/DroidSansMono/complete/Droid%20Sans%20Mono%20Nerd%20Font%20Complete.otf

Option 7: Unofficial Arch User Repository (AUR)

选项用于Arch Linux并且想要使用AUR包

以下字体可通过AUR packages在Arch Linux上:

Option 8: Patch Your Own Font

的选项打补丁你的自己的字体或完全自定义打补丁的字体

使用提供的Python命令行脚本从您自己的字体生成修补字体,以获得额外的新字形

请参见:Font Patcher供使用

  • 如果需要,请使用此选项想要使用其中一个fonts provided
  • 您仍需要将生成的字体复制到系统上的正确字体目录

修补您自己选择的字体以与VimDevIcons ➶

  • 要求:Python 2(或Python 3),python-fontforge包(版本20141231或稍后,请参阅install instructions)
  • OSX上的备用安装方法:brew install fontforge
  • 使用Docker的替代方法:Docker Hub
  • 用法:
./font-patcher PATH_TO_FONT
  • 替代用法:使用脚本标志使用FontForge二进制文件执行补丁程序:
./fontforge -script font-patcher PATH_TO_FONT
  • 使用Docker修补字体:
docker run -v /path/to/fonts:/in -v /path/for/output:/out nerdfonts/patcher [OPTIONS]
usage: font-patcher [-h] [-v] [-s] [-l] [-q] [-w] [-c] [--fontawesome]
                    [--fontawesomeextension] [--fontlinux] [--octicons]
                    [--powersymbols] [--pomicons] [--powerline]
                    [--powerlineextra] [--material] [--weather]
                    [--custom [CUSTOM]] [--postprocess [POSTPROCESS]]
                    [--removeligs] [--configfile [CONFIGFILE]]
                    [--progressbars | --no-progressbars] [--careful]
                    [-ext [EXTENSION]] [-out [OUTPUTDIR]]
                    font

Nerd Fonts Font Patcher: patches a given font with programming and development related glyphs

* Website: https://www.nerdfonts.com
* Version: 2.0.0
* Development Website: https://github.com/ryanoasis/nerd-fonts
* Changelog: https://github.com/ryanoasis/nerd-fonts/blob/master/changelog.md

positional arguments:
  font                  The path to the font to patch (e.g., Inconsolata.otf)

optional arguments:
  -h, --help            show this help message and exit
  -v, --version         show program's version number and exit
  -s, --mono, --use-single-width-glyphs
                        Whether to generate the glyphs as single-width not double-width (default is double-width)
  -l, --adjust-line-height
                        Whether to adjust line heights (attempt to center powerline separators more evenly)
  -q, --quiet, --shutup
                        Do not generate verbose output
  -w, --windows         Limit the internal font name to 31 characters (for Windows compatibility)
  -c, --complete        Add all available Glyphs
  --fontawesome         Add Font Awesome Glyphs (http://fontawesome.io/)
  --fontawesomeextension
                        Add Font Awesome Extension Glyphs (https://andrelzgava.github.io/font-awesome-extension/)
  --fontlinux, --fontlogos
                        Add Font Linux and other open source Glyphs (https://github.com/Lukas-W/font-logos)
  --octicons            Add Octicons Glyphs (https://octicons.github.com)
  --powersymbols        Add IEC Power Symbols (https://unicodepowersymbol.com/)
  --pomicons            Add Pomicon Glyphs (https://github.com/gabrielelana/pomicons)
  --powerline           Add Powerline Glyphs
  --powerlineextra      Add Powerline Glyphs (https://github.com/ryanoasis/powerline-extra-symbols)
  --material, --materialdesignicons, --mdi
                        Add Material Design Icons (https://github.com/templarian/MaterialDesign)
  --weather, --weathericons
                        Add Weather Icons (https://github.com/erikflowers/weather-icons)
  --custom [CUSTOM]     Specify a custom symbol font. All new glyphs will be copied, with no scaling applied.
  --postprocess [POSTPROCESS]
                        Specify a Script for Post Processing
  --removeligs, --removeligatures
                        Removes ligatures specified in JSON configuration file
  --configfile [CONFIGFILE]
                        Specify a file path for JSON configuration file (see sample: src/config.sample.json)
  --progressbars        Show percentage completion progress bars per Glyph Set
  --no-progressbars     Don't show percentage completion progress bars per Glyph Set
  --careful             Do not overwrite existing glyphs if detected
  -ext [EXTENSION], --extension [EXTENSION]
                        Change font file type to create (e.g., ttf, otf)
  -out [OUTPUTDIR], --outputdir [OUTPUTDIR]
                        The directory to output the patched font file to

示例

./font-patcher Droid\ Sans\ Mono\ for\ Powerline.otf
./font-patcher Droid\ Sans\ Mono\ for\ Powerline.otf -s -q
./font-patcher Droid\ Sans\ Mono\ for\ Powerline.otf --use-single-width-glyphs --quiet
./font-patcher Droid\ Sans\ Mono\ for\ Powerline.otf -w
./font-patcher Droid\ Sans\ Mono\ for\ Powerline.otf --windows --quiet
./font-patcher Droid\ Sans\ Mono\ for\ Powerline.otf --windows --pomicons --quiet
./font-patcher Inconsolata.otf --fontawesome
./font-patcher Inconsolata.otf --fontawesome --octicons --pomicons
./font-patcher Inconsolata.otf
docker run --rm -v ~/myfont/patchme:/in -v ~/myfont/patched:/out nerdfonts/patcher
docker run --rm -v ~/Desktop/myfont/patchme:/in -v ~/Desktop/myfont/patched:/out nerdfonts/patcher --fontawesome

我得把它们都补上字体补丁!

  • 供贡献者或开发者使用
  • 重新打补丁未打补丁的目录中的字体:
./gotta-patch-em-all-font-patcher\!.sh
  • 可以选择将其限制为特定的字体名称模式:
./gotta-patch-em-all-font-patcher\!.sh Hermit

贡献

看见contributing.md

不稳定的文件路径

⚠️警告:文件路径可能会根据版本的不同而更改(特别是主修版本颠簸)

引用发布分支和这个师傅分支,因为每个版本的路径都会更改

  • 例如:
    • ✅使用:https://github.com/ryanoasis/nerd-fonts/blob/0.9.0/patched-fonts/Hermit/Medium/complete/Hurmit%20Medium%20Nerd%20Font%20Complete.otf
    • ❌而不是:https://github.com/ryanoasis/nerd-fonts/blob/master/patched-fonts/Hermit/Medium/complete/Hurmit%20Medium%20Nerd%20Font%20Complete.otf

要修补的其他好字体

项目动机

看见Wiki: Project Purpose

更改日志

看见changelog.md

许可证

MIT©Ryan L McIntyre

Thefuck-一款出色的应用程序,可更正您之前的控制台命令

The Fuck

The Fuck是一款很棒的应用程序,灵感来自@liamosaur推文,它可以纠正之前控制台命令中的错误

更多示例:

➜ apt-get install vim
E: Could not open lock file /var/lib/dpkg/lock - open (13: Permission denied)
E: Unable to lock the administration directory (/var/lib/dpkg/), are you root?

➜ fuck
sudo apt-get install vim [enter/↑/↓/ctrl+c]
[sudo] password for nvbn:
Reading package lists... Done
...
➜ git push
fatal: The current branch master has no upstream branch.
To push the current branch and set the remote as upstream, use

    git push --set-upstream origin master


➜ fuck
git push --set-upstream origin master [enter/↑/↓/ctrl+c]
Counting objects: 9, done.
...
➜ puthon
No command 'puthon' found, did you mean:
 Command 'python' from package 'python-minimal' (main)
 Command 'python' from package 'python3' (main)
zsh: command not found: puthon

➜ fuck
python [enter/↑/↓/ctrl+c]
Python 3.4.2 (default, Oct  8 2014, 13:08:17)
...
➜ git brnch
git: 'brnch' is not a git command. See 'git --help'.

Did you mean this?
    branch

➜ fuck
git branch [enter/↑/↓/ctrl+c]
* master
➜ lein rpl
'rpl' is not a task. See 'lein help'.

Did you mean this?
         repl

➜ fuck
lein repl [enter/↑/↓/ctrl+c]
nREPL server started on port 54848 on host 127.0.0.1 - nrepl://127.0.0.1:54848
REPL-y 0.3.1
...

如果您不怕盲目运行更正后的命令,可以禁用REQUIRED_CONFIRMATION设置选项:

➜ apt-get install vim
E: Could not open lock file /var/lib/dpkg/lock - open (13: Permission denied)
E: Unable to lock the administration directory (/var/lib/dpkg/), are you root?

➜ fuck
sudo apt-get install vim
[sudo] password for nvbn:
Reading package lists... Done
...

安装

  • python (3.4+)
  • pip
  • python-dev

在MacOS上,您可以通过Homebrew(或Linux上的Linuxbrew)安装Fuck:

brew install thefuck

在Ubuntu/Mint上,使用以下命令安装Fuck:

sudo apt update
sudo apt install python3-dev python3-pip python3-setuptools
sudo pip3 install thefuck

在FreeBSD上,使用以下命令安装Fuck:

pkg install thefuck

在ChromeOS上,使用以下命令使用chromebrew安装Fuck:

crew install thefuck

在其他系统上,使用pip安装Fuck:

pip install thefuck

或者,您也可以使用操作系统包管理器(OS X、Ubuntu、Arch)

#建议您将此命令放在.bash_profile、.bashrc、.zshc或其他启动脚本中:

eval $(thefuck --alias)
# You can use whatever you want as an alias, like for Mondays:
eval $(thefuck --alias FUCK)

或者在您的shell配置中(bash、zsh、Fish、powershell、tcsh)

更改仅在新的shell会话中可用。要使更改立即可用,请运行source~/.bashrc(或您的shell配置文件,如.zshc)

要在没有确认的情况下运行已修复的命令,请使用–yes选项(或者简称为-y,如果您特别沮丧,则使用–hard):

fuck --yeah

要递归修复命令直到成功,请使用-r选项:

fuck -r
Back to Contents

卸载

pip3 install thefuck --upgrade

注意:别名功能在Fuck的1.34版中已更改

它是如何工作的

要删除,请颠倒安装过程:-从您的Bash、zsh、Fish、powershell、tcsh中删除或注释别名行。shell配置-使用软件包管理器(BREW、PIP3、pkg、Crew、pip)卸载二进制文件

创建您自己的规则

The Fuck 试图将前一条命令与规则相匹配。如果找到匹配项,则使用匹配的规则创建新命令并执行。默认情况下启用以下规则:

  • adb_unknown_command – fixes misspelled commands like adb logcta;
  • ag_literal – adds -Q to ag when suggested;
  • aws_cli – fixes misspelled commands like aws dynamdb scan;
  • az_cli – fixes misspelled commands like az providers;
  • cargo – runs cargo build instead of cargo;
  • cargo_no_command – fixes wrongs commands like cargo buid;
  • cat_dir – replaces cat with ls when you try to cat a directory;
  • cd_correction – spellchecks and correct failed cd commands;
  • cd_cs – changes cs to cd;
  • cd_mkdir – creates directories before cd’ing into them;
  • cd_parent – changes cd.. to cd ..;
  • chmod_x – add execution bit;
  • choco_install – append common suffixes for chocolatey packages;
  • composer_not_command – fixes composer command name;
  • conda_mistype – fixes conda commands;
  • cp_create_destination – creates a new directory when you attempt to cp or mv to a non existent one
  • cp_omitting_directory – adds -a when you cp directory;
  • cpp11 – adds missing -std=c++11 to g++ or clang++;
  • dirty_untar – fixes tar x command that untarred in the current directory;
  • dirty_unzip – fixes unzip command that unzipped in the current directory;
  • django_south_ghost – adds --delete-ghost-migrations to failed because ghosts django south migration;
  • django_south_merge – adds --merge to inconsistent django south migration;
  • docker_login – executes a docker login and repeats the previous command;
  • docker_not_command – fixes wrong docker commands like docker tags;
  • docker_image_being_used_by_container &dash removes the container that is using the image before removing the image;
  • dry – fixes repetitions like git git push;
  • fab_command_not_found – fix misspelled fabric commands;
  • fix_alt_space – replaces Alt+Space with Space character;
  • fix_file – opens a file with an error in your $EDITOR;
  • gem_unknown_command – fixes wrong gem commands;
  • git_add – fixes “pathspec ‘foo’ did not match any file(s) known to git.”;
  • git_add_force – adds --force to git add <pathspec>... when paths are .gitignore’d;
  • git_bisect_usage – fixes git bisect strt, git bisect goood, git bisect rset, etc. when bisecting;
  • git_branch_delete – changes git branch -d to git branch -D;
  • git_branch_delete_checked_out – changes git branch -d to git checkout master && git branch -D when trying to delete a checked out branch;
  • git_branch_exists – offers git branch -d foo, git branch -D foo or git checkout foo when creating a branch that already exists;
  • git_branch_list – catches git branch list in place of git branch and removes created branch;
  • git_branch_flag_0_to_flag_dash_v – undoes git branch 0v and runs git branch -v in its place;
  • git_checkout – fixes branch name or creates new branch;
  • git_clone_git_clone – replaces git clone git clone ... with git clone ...
  • git_commit_amend – offers git commit --amend after previous commit;
  • git_commit_reset – offers git reset HEAD~ after previous commit;
  • git_diff_no_index – adds --no-index to previous git diff on untracked files;
  • git_diff_staged – adds --staged to previous git diff with unexpected output;
  • git_fix_stash – fixes git stash commands (misspelled subcommand and missing save);
  • git_flag_after_filename – fixes fatal: bad flag '...' after filename
  • git_help_aliased – fixes git help <alias> commands replacing with the aliased command;
  • git_hook_bypass – adds --no-verify flag previous to git am, git commit, or git push command;
  • git_lfs_mistype – fixes mistyped git lfs <command> commands;
  • git_merge – adds remote to branch names;
  • git_merge_unrelated – adds --allow-unrelated-histories when required
  • git_not_command – fixes wrong git commands like git brnch;
  • git_pull – sets upstream before executing previous git pull;
  • git_pull_clone – clones instead of pulling when the repo does not exist;
  • git_pull_uncommitted_changes – stashes changes before pulling and pops them afterwards;
  • git_push – adds --set-upstream origin $branch to previous failed git push;
  • git_push_different_branch_names – fixes pushes when local branch name does not match remote branch name;
  • git_push_pull – runs git pull when push was rejected;
  • git_push_without_commits – Creates an initial commit if you forget and only git add ., when setting up a new project;
  • git_rebase_no_changes – runs git rebase --skip instead of git rebase --continue when there are no changes;
  • git_remote_delete – replaces git remote delete remote_name with git remote remove remote_name;
  • git_rm_local_modifications – adds -f or --cached when you try to rm a locally modified file;
  • git_rm_recursive – adds -r when you try to rm a directory;
  • git_rm_staged – adds -f or --cached when you try to rm a file with staged changes
  • git_rebase_merge_dir – offers git rebase (--continue | --abort | --skip) or removing the .git/rebase-merge dir when a rebase is in progress;
  • git_remote_seturl_add – runs git remote add when git remote set_url on nonexistent remote;
  • git_stash – stashes your local modifications before rebasing or switching branch;
  • git_stash_pop – adds your local modifications before popping stash, then resets;
  • git_tag_force – adds --force to git tag <tagname> when the tag already exists;
  • git_two_dashes – adds a missing dash to commands like git commit -amend or git rebase -continue;
  • go_run – appends .go extension when compiling/running Go programs;
  • go_unknown_command – fixes wrong go commands, for example go bulid;
  • gradle_no_task – fixes not found or ambiguous gradle task;
  • gradle_wrapper – replaces gradle with ./gradlew;
  • grep_arguments_order – fixes grep arguments order for situations like grep -lir . test;
  • grep_recursive – adds -r when you try to grep directory;
  • grunt_task_not_found – fixes misspelled grunt commands;
  • gulp_not_task – fixes misspelled gulp tasks;
  • has_exists_script – prepends ./ when script/binary exists;
  • heroku_multiple_apps – add --app <app> to heroku commands like heroku pg;
  • heroku_not_command – fixes wrong heroku commands like heroku log;
  • history – tries to replace command with the most similar command from history;
  • hostscli – tries to fix hostscli usage;
  • ifconfig_device_not_found – fixes wrong device names like wlan0 to wlp2s0;
  • java – removes .java extension when running Java programs;
  • javac – appends missing .java when compiling Java files;
  • lein_not_task – fixes wrong lein tasks like lein rpl;
  • long_form_help – changes -h to --help when the short form version is not supported
  • ln_no_hard_link – catches hard link creation on directories, suggest symbolic link;
  • ln_s_order – fixes ln -s arguments order;
  • ls_all – adds -A to ls when output is empty;
  • ls_lah – adds -lah to ls;
  • man – changes manual section;
  • man_no_space – fixes man commands without spaces, for example mandiff;
  • mercurial – fixes wrong hg commands;
  • missing_space_before_subcommand – fixes command with missing space like npminstall;
  • mkdir_p – adds -p when you try to create a directory without a parent;
  • mvn_no_command – adds clean package to mvn;
  • mvn_unknown_lifecycle_phase – fixes misspelled life cycle phases with mvn;
  • npm_missing_script – fixes npm custom script name in npm run-script <script>;
  • npm_run_script – adds missing run-script for custom npm scripts;
  • npm_wrong_command – fixes wrong npm commands like npm urgrade;
  • no_command – fixes wrong console commands, for example vom/vim;
  • no_such_file – creates missing directories with mv and cp commands;
  • omnienv_no_such_command – fixes wrong commands for goenv, nodenv, pyenv and rbenv (eg.: pyenv isntall or goenv list);
  • open – either prepends http:// to address passed to open or create a new file or directory and passes it to open;
  • pip_install – fixes permission issues with pip install commands by adding --user or prepending sudo if necessary;
  • pip_unknown_command – fixes wrong pip commands, for example pip instatl/pip install;
  • php_s – replaces -s by -S when trying to run a local php server;
  • port_already_in_use – kills process that bound port;
  • prove_recursively – adds -r when called with directory;
  • python_command – prepends python when you try to run non-executable/without ./ python script;
  • python_execute – appends missing .py when executing Python files;
  • python_module_error – fixes ModuleNotFoundError by trying to pip install that module;
  • quotation_marks – fixes uneven usage of ' and " when containing args’;
  • path_from_history – replaces not found path with a similar absolute path from history;
  • rails_migrations_pending – runs pending migrations;
  • react_native_command_unrecognized – fixes unrecognized react-native commands;
  • remove_shell_prompt_literal – remove leading shell prompt symbol $, common when copying commands from documentations;
  • remove_trailing_cedilla – remove trailing cedillas ç, a common typo for European keyboard layouts;
  • rm_dir – adds -rf when you try to remove a directory;
  • scm_correction – corrects wrong scm like hg log to git log;
  • sed_unterminated_s – adds missing ‘/’ to sed‘s s commands;
  • sl_ls – changes sl to ls;
  • ssh_known_hosts – removes host from known_hosts on warning;
  • sudo – prepends sudo to the previous command if it failed because of permissions;
  • sudo_command_from_user_path – runs commands from users $PATH with sudo;
  • switch_lang – switches command from your local layout to en;
  • systemctl – correctly orders parameters of confusing systemctl;
  • terraform_init.py – run terraform init before plan or apply;
  • test.py – runs py.test instead of test.py;
  • touch – creates missing directories before “touching”;
  • tsuru_login – runs tsuru login if not authenticated or session expired;
  • tsuru_not_command – fixes wrong tsuru commands like tsuru shell;
  • tmux – fixes tmux commands;
  • unknown_command – fixes hadoop hdfs-style “unknown command”, for example adds missing ‘-‘ to the command on hdfs dfs ls;
  • unsudo – removes sudo from previous command if a process refuses to run on superuser privilege.
  • vagrant_up – starts up the vagrant instance;
  • whois – fixes whois command;
  • workon_doesnt_exists – fixes virtualenvwrapper env name os suggests to create new.
  • yarn_alias – fixes aliased yarn commands like yarn ls;
  • yarn_command_not_found – fixes misspelled yarn commands;
  • yarn_command_replaced – fixes replaced yarn commands;
  • yarn_help – makes it easier to open yarn documentation;
Back to Contents

默认情况下,仅在特定平台上启用以下规则:

  • apt_get – installs app from apt if it not installed (requires python-commandnotfound / python3-commandnotfound);
  • apt_get_search – changes trying to search using apt-get with searching using apt-cache;
  • apt_invalid_operation – fixes invalid apt and apt-get calls, like apt-get isntall vim;
  • apt_list_upgradable – helps you run apt list --upgradable after apt update;
  • apt_upgrade – helps you run apt upgrade after apt list --upgradable;
  • brew_cask_dependency – installs cask dependencies;
  • brew_install – fixes formula name for brew install;
  • brew_reinstall – turns brew install <formula> into brew reinstall <formula>;
  • brew_link – adds --overwrite --dry-run if linking fails;
  • brew_uninstall – adds --force to brew uninstall if multiple versions were installed;
  • brew_unknown_command – fixes wrong brew commands, for example brew docto/brew doctor;
  • brew_update_formula – turns brew update <formula> into brew upgrade <formula>;
  • dnf_no_such_command – fixes mistyped DNF commands;
  • nixos_cmd_not_found – installs apps on NixOS;
  • pacman – installs app with pacman if it is not installed (uses yay or yaourt if available);
  • pacman_invalid_option – replaces lowercase pacman options with uppercase.
  • pacman_not_found – fixes package name with pacman, yay or yaourt.
  • yum_invalid_operation – fixes invalid yum calls, like yum isntall vim;

以下命令与Fuck捆绑在一起,但默认情况下不启用:

  • git_push_force – adds --force-with-lease to a git push (may conflict with git_push_pull);
  • rm_root – adds --no-preserve-root to rm -rf / command.

设置

要添加您自己的规则,请在~/.config/TheMASH/Rules中创建一个名为your-Rule-name.py的文件。规则文件必须包含两个函数:

match(command: Command) -> bool
get_new_command(command: Command) -> str | list[str]

此外,规则可以包含可选函数:

side_effect(old_command: Command, fixed_command: str) -> None

规则还可以包含可选变量Enabled_by_Default、Requires_Output和Priority

命令有三个属性:script、output和script_part。您的规则不应更改命令

规则API在3.0中发生了更改:要访问规则的设置,请使用Fuck.conf导入设置将其导入

Settings是一个特殊的对象,它由~/.config/the妈的/settings.py和env中的值组合而成(参见下面的更多内容)

使用sudo运行脚本的一个简单示例规则:

def match(command):
    return ('permission denied' in command.output.lower()
            or 'EACCES' in command.output)


def get_new_command(command):
    return 'sudo {}'.format(command.script)

# Optional:
enabled_by_default = True

def side_effect(command, fixed_command):
    subprocess.call('chmod 777 .', shell=True)

priority = 1000  # Lower first, default is 1000

requires_output = True

更多规则示例、用于规则的实用程序函数、特定于应用程序/操作系统的帮助器

带规则的第三方包

可以在文件$XDG_CONFIG_HOME/the他妈的/settings.py($XDG_CONFIG_HOME默认为~/.config)中更改几个Fuck参数:

  • rules – list of enabled rules, by default thefuck.const.DEFAULT_RULES;
  • exclude_rules – list of disabled rules, by default [];
  • require_confirmation – requires confirmation before running new command, by default True;
  • wait_command – the max amount of time in seconds for getting previous command output;
  • no_colors – disable colored output;
  • priority – dict with rules priorities, rule with lower priority will be matched first;
  • debug – enables debug output, by default False;
  • history_limit – the numeric value of how many history commands will be scanned, like 2000;
  • alter_history – push fixed command to history, by default True;
  • wait_slow_command – max amount of time in seconds for getting previous command output if it in slow_commands list;
  • slow_commands – list of slow commands;
  • num_close_matches – the maximum number of close matches to suggest, by default 3.
  • excluded_search_path_prefixes – path prefixes to ignore when searching for commands, by default [].

settings.py的一个示例:

rules = ['sudo', 'no_command']
exclude_rules = ['git_push']
require_confirmation = True
wait_command = 10
no_colors = False
priority = {'sudo': 100, 'no_command': 9999}
debug = False
history_limit = 9999
wait_slow_command = 20
slow_commands = ['react-native', 'gradle']
num_close_matches = 5

或通过环境变量:

  • THEFUCK_RULES – list of enabled rules, like DEFAULT_RULES:rm_root or sudo:no_command;
  • THEFUCK_EXCLUDE_RULES – list of disabled rules, like git_pull:git_push;
  • THEFUCK_REQUIRE_CONFIRMATION – require confirmation before running new command, true/false;
  • THEFUCK_WAIT_COMMAND – the max amount of time in seconds for getting previous command output;
  • THEFUCK_NO_COLORS – disable colored output, true/false;
  • THEFUCK_PRIORITY – priority of the rules, like no_command=9999:apt_get=100,
    rule with lower priority will be matched first;
  • THEFUCK_DEBUG – enables debug output, true/false;
  • THEFUCK_HISTORY_LIMIT – how many history commands will be scanned, like 2000;
  • THEFUCK_ALTER_HISTORY – push fixed command to history true/false;
  • THEFUCK_WAIT_SLOW_COMMAND – the max amount of time in seconds for getting previous command output if it in slow_commands list;
  • THEFUCK_SLOW_COMMANDS – list of slow commands, like lein:gradle;
  • THEFUCK_NUM_CLOSE_MATCHES – the maximum number of close matches to suggest, like 5.
  • THEFUCK_EXCLUDED_SEARCH_PATH_PREFIXES – path prefixes to ignore when searching for commands, by default [].

例如:

export THEFUCK_RULES='sudo:no_command'
export THEFUCK_EXCLUDE_RULES='git_pull:git_push'
export THEFUCK_REQUIRE_CONFIRMATION='true'
export THEFUCK_WAIT_COMMAND=10
export THEFUCK_NO_COLORS='false'
export THEFUCK_PRIORITY='no_command=9999:apt_get=100'
export THEFUCK_HISTORY_LIMIT='2000'
export THEFUCK_NUM_CLOSE_MATCHES='5'
Back to Contents

实验即时模式

如果您希望制定一组特定的非公共规则,但仍希望与其他人共享这些规则,请创建一个名为TheMASH_CONTRIB_*的包,其结构如下:

thefuck_contrib_foo
  thefuck_contrib_foo
    rules
      __init__.py
      *third-party rules*
    __init__.py
    *third-party-utils*
  setup.py

操蛋将在规则模块中查找规则

Back to Contents

发展中

Fuck的默认行为需要时间来重新运行先前的命令。在即时模式下,Fuck通过使用脚本记录输出,然后读取日志来节省时间

目前,即时模式仅支持带有bash或zsh的Python3。为了正常工作,还需要禁用zsh的自动更正功能

要启用即时模式,请向.bashrc、.bash_profile或.zshc中的别名初始化添加–enable-explementation-instant-mode

请参阅CONTRIBUTING.md

eval $(thefuck --alias --enable-experimental-instant-mode)