157

我曾经读到,在 shell 中为临时文件获取唯一文件名的一种方法是使用双美元符号 ( $$)。这确实会产生一个不时变化的数字......但如果你重复调用它,它会返回相同的数字。(解决办法就是利用时间。)

我很想知道$$实际上是什么,以及为什么建议将其作为生成唯一文件名的一种方式。

4

12 回答 12

125

$$是 bash 中的进程 ID (PID)。使用$$是一个坏主意,因为它通常会产生竞争条件,并允许您的 shell 脚本被攻击者破坏。例如,请参阅所有这些创建不安全临时文件并不得不发布安全建议的人。

相反,使用mktemp. mktemp的Linux 手册页非常好。这是其中的一些示例代码:

tempfoo=`basename $0`
TMPFILE=`mktemp -t ${tempfoo}` || exit 1
echo "program output" >> $TMPFILE
于 2008-09-17T00:13:43.507 回答
112

在 Bash$$中是进程 ID,如注释中所述,由于各种原因,将其用作临时文件名是不安全的。

对于临时文件名,使用mktemp命令。

于 2008-09-17T00:02:13.923 回答
23

$$ 是当前进程的id。

于 2008-09-17T00:01:48.480 回答
8

类 UNIX 操作系统中的每个进程都有一个(临时)唯一标识符,即 PID。同时运行的两个进程不能有相同的 PID,$$ 指的是运行脚本的 bash 实例的 PID。

不是一个唯一标识符,因为它永远不会被重用(实际上,PID 经常被重用)。它给你的是一个数字,如果另一个人运行你的脚本,他们将在你的脚本仍在运行时获得不同的标识符。一旦你的 PID 死了,PID 可能会被回收,其他人可能会运行你的脚本,获得相同的 PID,从而获得相同的文件名。

因此,说“$$ 给出一个文件名,这样如果其他人在我的实例仍在运行时运行相同的脚本,他们将得到一个不同的名称”,这真的是很理智的。

于 2008-09-17T00:05:09.347 回答
5

$$ 是您的 PID。它并不会真正生成唯一的文件名,除非你很小心并且没有其他人以完全相同的方式这样做。

通常你会创建类似 /tmp/myprogramname$$

有很多方法可以解决这个问题,如果您正在写入其他人可以写入的位置,那么在许多操作系统上预测您将拥有什么 PID 并搞砸并不难——想象您正在运行以 root 身份创建 /tmp/yourprogname13395 作为指向 /etc/passwd 的符号链接,然后您将其写入。

这是在 shell 脚本中做的一件坏事。如果您要使用临时文件来做某事,您应该使用更好的语言,它至少可以让您添加“独占”标志来打开(创建)文件。然后你可以确定你没有破坏其他东西。

于 2008-09-17T00:06:00.420 回答
4

$$ 是运行脚本的 shell 解释器的 pid(进程 ID)。目前在系统上运行的每个进程都是不同的,但随着时间的推移,pid 会环绕,并且在您退出后最终会有另一个具有相同 pid 的进程。只要您正在运行,pid 对您来说是唯一的。

从上面的定义很明显,无论你在脚本中使用多少次 $$,它都会返回相同的数字。

您可以使用 /tmp/myscript.scratch.$$ 作为临时文件,用于不需要非常可靠或安全的东西。在脚本末尾删除此类临时文件是一个很好的做法,例如,使用 trap 命令:

trap "echo 'Cleanup in progress'; rm -r $TMP_DIR" EXIT
于 2008-09-17T00:08:20.430 回答
3

$$ 是当前 shell 进程的 pid。这不是生成唯一文件名的好方法。

于 2008-09-17T00:01:50.540 回答
2

它是 bash 进程的进程 ID。没有并发进程将永远具有相同的 PID。

于 2008-09-17T00:02:44.733 回答
2

$$ 是运行脚本的 shell 的进程 ID。有关更多详细信息,请参见 sh 或 bash 的手册页。可以使用命令行“man sh”或通过在网上搜索“shell manpage”来找到手册页

于 2008-09-17T00:05:11.857 回答
2

让我再说一遍 emk 的答案——不要将 $$ 本身用作“独特”的任何东西。对于文件,使用 mktemp。对于同一 bash 脚本中的其他 ID,请使用 "$$$(date +%s%N)" 以获得相当好的唯一性。

 -k
于 2008-09-17T00:29:10.287 回答
1

鱼壳( 3.1.2) 中:

$符号也可以多次使用,作为一种“取消引用”运算符(C 或 C++ 中的 *)

set bar bazz
set foo bar
echo $foo # bar
echo $$foo # same as echo $bar → bazz
于 2020-11-15T22:29:33.073 回答
0

此外,您可以通过此命令获取登录用户名。例如。

echo $(</proc/$$/login id). After that, you need to use getent command.
于 2018-02-12T11:05:54.190 回答