Shell里面的&符号、>符号的细节理解

1、问题1

当我在Linux用screen来管理服务时,由于输入的命令最后 多了个 &,

导致在screen -ls 查看返回结果中,一直都找不到刚才启动的服务。

最后才发现是这个 “&” 的缘故。

screen -S filescompare 后

正确的的命令应当是:

uvicorn your_app:app --reload --host 0.0.0.0 --port 9000 > uvicorn.log 2>&1

而我输入的命令最后多了个 &

uvicorn your_app:app --reload --host 0.0.0.0 --port 9000 > uvicorn.log 2>&1 &

 

因为在命令末尾加了 &。我来解释一下这个差异。

&screen 的关系

  • &这是 Shell 命令中的一个特殊符号,表示将命令放到后台执行。当你在命令末尾加上 &,Shell 会在后台启动该进程并立即返回到命令行。虽然进程会继续在后台运行,但它不再与当前的 shell 会话关联。这意味着,如果你退出当前的 shell,后台进程也会受到影响,可能会被杀死。

  • screenscreen 是一个终端复用工具,它可以将进程与当前终端会话分离(通过 Ctrl+A + D)。分离后,进程继续在后台运行,但它会一直与 screen 会话关联,即使你关闭终端或退出,进程依然会持续运行,直到你明确结束它。通过 screen -ls 可以查看当前活动的会话,使用 screen -r 可以恢复这些会话。

你遇到的问题

  • 当你使用 & 来后台运行命令时,进程会在后台运行,但由于没有使用 screen,这个进程就没有与一个持久的终端会话关联。
  • 由于没有 screen 会话,screen -ls 不会显示任何内容,即使进程本身在后台通过 lsof 可以看到它在监听端口。

解决方案

如果你希望通过 screen 来管理进程,避免使用 & 将其放到后台,应该通过以下方式操作:

1. 通过 screen 启动服务

在启动服务时,不要加上 &,直接在 screen 会话中启动命令。这样可以确保进程与 screen 会话关联,即使退出终端,进程仍会在后台持续运行,并且能够通过 screen -ls 查看和恢复。

screen -S filescompare
uvicorn your_app:app --reload --host 0.0.0.0 --port 9000 > uvicorn.log 2>&1

2.分离 screen 会话

一旦服务启动,在 screen 会话中按下 Ctrl + A,然后按 D 来分离会话。此时进程将继续在后台运行

3.查看 screen 会话

使用 screen -ls 查看当前的 screen 会话,并可以恢复到该会话。

screen -ls

4.恢复 screen 会话

如果你退出并希望重新进入会话,可以使用 screen -r <session_name> 或者通过会话ID(如 filescompare来恢复。

screen -r filescompare

总结

  • 使用 screen不要加 &,因为 screen 本身已经负责在后台管理进程,并保持进程与会话的关联。
  • 使用 screen 可以让你管理进程,即使退出终端或断开连接,进程仍然会继续运行。

 

2、问题2

对于如下命令,如何理解各参数的含义,尤其最后几个。

nohup uvicorn your_app:app --reload --host 0.0.0.0 --port 9000 > uvicorn.log 2>&1 &

1. nohup

  • nohupno hang up 的缩写,表示“忽略挂起信号”。
  • 它用于确保命令在退出当前会话(比如关闭终端)后依然继续执行。通常,终端会向正在运行的进程发送 SIGHUP(挂起信号)来终止进程,但使用 nohup 后,进程会忽略这个信号,继续在后台运行。
  • 使用 nohup 可以确保在关闭终端或断开 SSH 连接时,进程仍然可以继续运行,直到被明确终止。

2. uvicorn your_app:app

  • uvicorn 是一个轻量级的 ASGI 服务器(Asynchronous Server Gateway Interface),常用于运行 FastAPI 应用。uvicorn 用于启动 FastAPI(或者其他基于 ASGI 的框架)应用程序。
  • your_app:app
    • your_app 是 Python 文件(不需要扩展名 .py),其中包含 FastAPI 应用的代码。
    • app 是 Python 文件中的 FastAPI 实例。通常在 FastAPI 中,你会创建一个应用实例 app = FastAPI(),这个实例就是这里提到的 app
    • 这部分是告诉 uvicorn 需要运行哪个 Python 文件中的哪个 FastAPI 实例。

3. --reload

  • --reloaduvicorn 的一个选项,用来开启自动重载功能。
  • 在开发阶段,开启 --reload 后,当你修改了代码(例如,修改了 FastAPI 的路由或逻辑),uvicorn 会自动检测到代码变化并重启应用程序,而无需手动停止和重新启动服务。
  • 注意: 这个选项在生产环境中应该禁用,因为它会增加不必要的开销。

4. --host 0.0.0.0

  • --host 用来指定服务器绑定的 IP 地址。
  • 0.0.0.0 表示允许所有网络接口的访问,也就是说,服务器会监听所有 IP 地址的请求,通常用于让服务可以被外部访问。
  • 如果你只希望允许本地访问,可以将 host 设置为 127.0.0.1(localhost),这会将服务限制在本地计算机上。

5. --port 9000

  • --port 用来指定服务器监听的端口号。
  • 9000 表示你的应用将会监听 9000 端口,外界可以通过 http://<服务器地址>:9000 来访问你的 FastAPI 应用。
  • 你可以根据需要选择不同的端口号,但确保该端口没有被其他进程占用。

6. > uvicorn.log

  • > 是输出重定向符号,用来将命令的标准输出(STDOUT)重定向到文件中。
  • uvicorn.log 是指定将标准输出内容写入到 uvicorn.log 文件中。这样,应用运行时的输出(如日志信息、调试信息等)会被保存到这个文件,而不会显示在终端中。

7. 2>&1

  • 2> 是错误输出重定向符号,它表示将标准错误输出(STDERR)重定向到指定的文件或目标。
  • &1 表示将标准错误输出(文件描述符 2)重定向到标准输出(文件描述符 1)的目标。
  • 2>&1 的作用是将标准错误标准输出合并并都重定向到同一个文件。在这个例子中,标准错误(例如程序的错误日志)和标准输出(正常的程序日志)都会被写入到 uvicorn.log 文件中。

8. &

  • & 是一个后台运行符号,它将命令放入后台执行,并且让终端立即返回到命令行。
  • 如果没有 &,命令会在前台运行,终端会被阻塞,直到命令完成(例如应用程序终止)。
  • 使用 & 后,命令在后台运行,终端可以继续接受其他命令,而不需要等待后台进程完成。即使你关闭了终端,进程也会继续运行(但是这时仍然可能会因为终端关闭而中断,如果没有使用 nohup)。

总结

  • nohup:确保进程在终端关闭后仍然继续运行。
  • uvicorn your_app:app:启动 FastAPI 应用,your_app 是包含应用的文件名,app 是 FastAPI 实例。
  • --reload:启用自动重载功能(通常用于开发阶段)
  • --host 0.0.0.0:允许外部访问,监听所有网络接口。
  • --port 9000:设置应用监听的端口号。
  • > uvicorn.log:将标准输出重定向到 uvicorn.log 文件。
  • 2>&1将标准错误输出合并到标准输出,重定向到同一个日志文件。
  • &将命令放入后台运行

因此,整体命令的作用是:在后台启动一个 FastAPI 应用,监听所有网络接口的 9000 端口,且输出和错误日志都写入 uvicorn.log 文件,并且即使关闭终端,进程依然会继续运行。

 

3、问题3

为什么这两个要连着一起写?2>&1

1. 文件描述符(File Descriptors)

在 Unix/Linux 系统中,所有的输入输出都通过文件描述符来进行管理。标准的输入输出有三个主要的文件描述符:

  • 标准输入(STDIN):文件描述符 0,用于输入(通常是键盘输入)。
  • 标准输出(STDOUT):文件描述符 1,用于正常输出(通常是显示在终端屏幕上的信息)。
  • 标准错误输出(STDERR):文件描述符 2,用于输出错误信息(通常也是显示在终端屏幕上)。

2. >2> 的作用

  • >:是重定向符号,表示将输出重定向到一个文件或其他地方。默认情况下,> 会重定向标准输出(STDOUT)。

    例如,echo "Hello" > output.txt 会将 "Hello" 输出到 output.txt 文件中,而不是显示在终端。

  • 2>:用于重定向 标准错误输出(STDERR)。2 是文件描述符 2,表示标准错误。比如,echo "Error" > error.txt 会将 "Error" 输出到 error.txt 文件中。如果你没有使用 2>,则错误信息默认会显示在终端。

3. 2>&1 的含义

2>&1 的意思是将 标准错误输出(2) 重定向到 标准输出(1) 的地方。

  • 2> 表示你要重定向标准错误。
  • &1 代表将重定向的目标设置为 标准输出(文件描述符 1)。

所以,2>&1 就是告诉系统:“将标准错误输出(2)发送到标准输出(1)所指向的位置。

4. 为什么要连着一起写?

它们必须连在一起写的原因是:

  • > 本身是一个操作符,用来表示重定向。而 &1 是告诉系统去指向文件描述符 1(标准输出)。如果没有 &,就会发生语法错误。
  • 2> 表示重定向错误输出到某个目标,而 &1 告诉它目标是标准输出。系统首先会解析 2> 然后将它指向 &1 这个目标。

5. 举个例子:

假设你有一个命令,它同时输出正常的信息和错误信息:

echo "Normal output"
echo "Error output" >&2

这里,第一条命令会输出正常信息,第二条命令会输出错误信息。输出会像这样:

Normal output
Error output

如果你想把它们都写入一个文件中,可以使用 2>&1 来实现:

echo "Normal output" > output.log
echo "Error output" >&2 >> output.log

如果你想将这两种输出合并并都写入同一个文件,你可以这样做:

command > output.log 2>&1

这将做以下几件事:

  1. command > output.log:将标准输出(STDOUT)写入 output.log 文件。
  2. 2>&1:将标准错误(STDERR)重定向到标准输出(STDOUT)的位置,也就是 output.log 文件。因为你已经将标准输出重定向到文件了,错误输出也会被写入同一个文件。

6. 总结:

  • 2>:重定向标准错误输出。
  • >&1:告诉系统将错误输出重定向到标准输出的位置。
  • 2>&1:将标准错误输出重定向到标准输出,最终两者都会输出到同一个文件或流中。

这个组合可以帮助你将程序的所有输出(无论是正常的还是错误的)都合并到同一个文件中,从而便于调试和记录日志。

 

4、问题4:“将标准错误输出(2)发送到标准输出(1)所指向的位置。” 说的有点拗口,举个通俗易懂的例子方便理解。

例子:邮件的“发件箱”和“垃圾箱”

假设你在公司工作,每天会收到两类邮件:

  1. 正常邮件(比如工作任务,文件等),你会把它们放到“发件箱”。
  2. 错误邮件(比如系统错误提示,或者需要修正的工作事项),你会把它们放到“垃圾箱”。

目标:

现在假设你想让所有邮件(无论是正常邮件还是错误邮件)都存放在同一个文件夹中,方便以后查看。那么,你的目标就是将 垃圾箱的邮件(错误邮件)移到 发件箱(正常邮件)里,这样它们就都放在同一个地方了。

真实场景:

在命令行中,标准输出(正常输出)就像“发件箱”,而 标准错误输出(错误输出)就像“垃圾箱”。我们想要把错误输出也放到和正常输出相同的地方——就像把“垃圾箱”的邮件放进“发件箱”一样。

2>&1 解释:

  • 2> 是指将 错误输出(2) 重定向。
  • &1 是指将重定向的目标指向 标准输出(1),也就是发件箱

所以,2>&1 就是“把错误输出放进标准输出的地方”,也就是将垃圾箱里的邮件放进发件箱里。

更简单的类比:

  • 标准输出(1) 就是你正常收到的邮件(发件箱)。
  • 标准错误(2) 就是错误的邮件(垃圾箱)。
  • 2>&1 就是把垃圾箱的邮件转移到发件箱。

举个命令的例子:

echo "Hello, World!" > output.log
echo "Error occurred!" >&2

上面的两条命令:

  • 第一条命令会把 "Hello, World!" 写到 output.log 文件里。
  • 第二条命令会把 "Error occurred!" 写到错误输出流。

但如果你想把这两条消息都写入同一个文件中,你可以这样做:

echo "Hello, World!" > output.log
echo "Error occurred!" >&2 >> output.log  

或者你可以合并这两个输出,写到同一个文件:

command > output.log 2>&1

这样,无论是正常信息还是错误信息都会都写入 output.log 文件

总结:

  • > 是将输出“发到”文件里。
  • 2> 是将错误输出“发到”另一个地方。
  • 2>&1 就是将错误输出放到和正常输出相同的地方,最终两者都在一个文件里。

 

5、问题5:

echo "Error occurred!" >&2 >> output.log 中,连着两个 >> 这是什么意思?和一个>区别是在哪里?

2. 具体例子

  • echo "Hello, World!" > output.log:这条命令会将 "Hello, World!" 写入到 output.log 文件。如果 output.log 已经存在,它会 覆盖 文件的内容。

  • echo "New line" >> output.log:这条命令会将 "New line" 追加到 output.log 文件的末尾。如果 output.log 不存在,它会 创建 文件并写入内容。

3. 你的命令:echo "Error occurred!" >&2 >> output.log

这条命令其实是 两个操作 结合在一起:

  1. >&2:这部分表示将输出重定向到 标准错误输出(文件描述符 2)。这意味着 "Error occurred!" 不是输出到标准输出(显示在终端屏幕上),而是输出到错误流。

  2. >> output.log:接着,它会将错误输出内容 追加 output.log 文件末尾。

4. 为什么要连着两个符号?

你可能会觉得为什么这里会有两个 > 符号。其实,它们各自做了不同的工作:

  • > 重定向操作符,第一个 > 用来重定向错误输出(2>),或者标准输出(>)。
  • >> 用来将输出追加到文件,而不是覆盖文件内容。

因此,echo "Error occurred!" >&2 >> output.log 的意思是:

  1. "Error occurred!" 输出到标准错误流(>&2)。
  2. 然后把这个错误输出 追加output.log 文件中(>> output.log)。

5. 总结

  • > 用于 覆盖 文件内容,或重定向到指定的输出。
  • >> 用于 追加 内容到文件,而不覆盖原文件。
  • echo "Error occurred!" >&2 >> output.log 中,>&2 将输出到标准错误流,然后通过 >> 将错误流追加到 output.log 文件。

 

 

 

 

 

 

 

 

 

 

 

posted @ 2025-01-22 16:59  AlphaGeek  阅读(305)  评论(0)    收藏  举报