创建文件并设置权限的单行命令

76

我正在使用以下两个命令创建一个0B文件并将其扩展名设置为644

touch filename.ext
chmod 777 filename.txt

我想问的是在Unix(Korn Shell)中是否有任何单个命令可以一次性完成两件事情,即创建一个具有所需权限的0B文件?


6
无论你想要实现什么目的,“chmod 777”都是错误且危险的!你应该调整你的代码以适当的权限(在大多数情况下,类似于755);如果你已经在公共主机上拥有可由任何人写入的系统文件,请重新安装系统并使用合理的权限,并开始调查你是否通过过失犯罪违法了。 - tripleee
将其扩展名设置为644。我不知道“extn”代表什么,但似乎644模式是期望的结果。现在已经太晚编辑了,因为所有答案都假定777。 - Amir
8个回答

83
install -m 777 /dev/null filename.txt

11
安装一个目录:install -m 700 -d /tmp/mydir - Fernando Fabreti
1
对于一个新的脚本文件,install /dev/null script.sh 很好用,因为 install 的默认权限是 755 - CJ Dennis
“install” 用于此目的。但不幸的是,大多数其他方法不会覆盖现有文件,但“install”会这样做。 - midnite
3
值得注意的是,在目录方面,可以使用老式的指令 mkdirmkdir -m 700 /tmp/mydir - Cromax
-m 代表 --mode=MODE-o, --owner=OWNER-g, --group=GROUP 选项也很有用。 - Константин Ван

18

首先,您绝不能将任何内容设置为777权限。这是一个巨大的安全问题,也没有必要这么做。对于此问题,我将假设您希望创建的文件权限比默认值更安全,例如600

使用大多数bash工具来安全地创建和更改文件权限并没有一种通用的方法。即使在Paul的答案中使用了棘手的重定向技巧,实际上也会短暂地创建一个具有默认权限的文件,然后重置它们。除非创建程序在节点创建时向操作系统发送非常特定的请求,否则所有新文件都将根据系统umask值创建。 133的掩码很常见,这意味着您的文件将从一开始就以644权限创建。

除了使用chmod命令在创建文件后设置文件权限外,您还可以使用umask命令告诉系统您想要的默认值。

$ umask 077
$ touch test_file
$ ls -l test_file
-rw------- 1 user group 0 Jan 24 22:43 test_file

请注意,该文件已使用600权限创建。

在您关闭shell或手动设置其他值之前,此权限将对在shell中运行的所有命令生效。如果您想要使用此结构来运行单个命令(甚至是一小组命令),将命令隔离在子shell中可能会很有用。

$ (umask 077 ; touch test_file)
请注意,您将括号中的任何其他内容都将使用该umask,但一旦关闭它,您就会回到先前的环境。

1
永远不要将任何东西设置为777是什么意思?在nginx下上传所有网站的文件夹感觉完美。 - Vasilii Suricov
1
@Vasilii 那么你的Web服务器就像一块起司布一样充满了漏洞。如果你将任何东西(更不用说公开服务的文件夹)设置为777,那么它就不安全了,你留下了所有的大门敞开。 - Caleb
1
停止服务器的左侧 - Vasilii Suricov
1
@VasiliiSuricov 正确的解决方案涉及几个方面:目录应该被与 Web 服务器相同的用户“拥有”,具有受限权限,被标记为包含临时文件,确保上传的任何东西都不能获得 mode 7(执行,+x)权限,并确保告诉 Web 服务器里面的任何内容都不应该运行(例如,PHP 文件只能作为原始内容下载,而不能作为代码“运行”)。 - Caleb
这很好,但umask无法设置执行位。 - midnite

17

对于bash,只需要使用文件重定向和历史扩展的chmod命令:

chmod 777 filename.txt>>!#:2

对于kshzsh,您必须放弃历史扩展(如上所示,可能还有其他方法)并使用:

chmod 644 filename>>filename

对于任何你没有(而且真的不需要)历史扩展功能的shell脚本,也请使用上述方法。


2
使用这个技巧,在进行更改之前,文件注释仍会以默认的umask权限创建。这可能会失败(电源故障、奇怪的ACL、文件系统问题等),并在系统上留下具有错误权限的文件。这是一个单行shell命令,但由shell执行两个步骤。设置umask是确保在创建文件时以所需权限创建文件的正确方法。 - Caleb
这可能是最佳方法,但可读性较差。您能解释一下 !#:2 部分吗? - midnite
1
@midnite !#:2 是一个历史命令:! 标记历史命令的开始;# 指代 这个 命令;:2 指代这个命令的第二个参数(即 filename.txt)。 - Paul Evans
@PaulEvans 我知道使用 >> 可以“工作”,但那只是在文件不存在时。如果它已经存在并且有内容,你将会得到错误的内容(OP 想要“一个 0B 文件”)。> 才是正确的版本。此外,重定向 chmod 的输出真的没有意义。这会让人觉得有输出需要重定向,但实际上并没有。这种方法还依赖于 shell 的微妙行为(首先创建输出重定向文件,然后运行 chmod),并且仍然遭受相同的问题(在两个非原子步骤中创建文件,然后更改权限)。 - Ken Williams
@KenWilliams,OP是:创建一个0B的文件 - Paul Evans
显示剩余2条评论

16
如果您想要创建的文件不仅为空,而且具有内容和模式,您可以在bash中使用install来进行进程替换:

如果您想要创建的文件不仅为空,而且具有内容和模式,您可以在bash中使用install来进行进程替换:

install -m 755 <(echo commands go here) newscript

<() 将输出放入临时文件中 (进程替换)


1
非常有帮助,能够使用类似sed的查找和替换机制安装输入文件。 - hariszaman

9
您可以创建自己的命令:
create () {
    touch "$1"
    chmod "$2" "$1"
}

create filename.ext 644

1
不,我认为我没有正确地放置查询……这不是关于特定权限或特定文件名的问题……而子程序部分是我正在使用的片段……我只是想知道是否有一个单一的命令可以同时完成两件事情……就像对于目录我们有mkdir -m 777 dirname……同样的。 - user3075776

5
你的文件没有默认的666权限的唯一原因是 umask。如果你禁用了umask
umask 0

当你触碰文件时,它会自动以权限666结束。通常情况下,将文本文件设置为可执行并不是一个好主意。禁用umask后,目录将以777权限结束。

chicks@freecandy /tmp $ umask
0022
chicks@freecandy /tmp $ touch x
chicks@freecandy /tmp $ mkdir xx

chicks@freecandy /tmp $ umask 0
chicks@freecandy /tmp $ touch y
chicks@freecandy /tmp $ mkdir yy

chicks@freecandy /tmp $ ls -ld x xx y yy                                                                                  
-rw-r--r-- 1 chicks chicks  484 Jan 24 14:37 x
drwxr-xr-x 2 chicks chicks 4096 Jan 24 14:37 xx
-rw-rw-rw- 1 chicks chicks    0 Jan 24 14:37 y
drwxrwxrwx 2 chicks chicks 4096 Jan 24 14:37 yy

如何在之后将 umask 更改回其先前的值? - SherylHohman
1
在更改umask之前启动一个新的shell,然后您只需退出该shell即可恢复旧的umask。https://unix.stackexchange.com/a/65890/79839 - chicks

3

touch filename.ext && chmod 777 $_

$_是最近的参数。

但正如其他人所说,777不是一个好主意。


0

将其应用于Docker

由于Docker和Alpine的存在,我想有很多人对创建可执行的单行命令感兴趣,而不需要bash-isms的帮助。使用install非常简单。

$ docker build -t temp - <<EOF
FROM alpine
RUN echo "date" | install -m 775 /dev/stdin /bin/now
CMD /bin/now
EOF

Sending build context to Docker daemon  2.048kB
Step 1/3 : FROM alpine
 ---> d6e46aa2470d
Step 2/3 : RUN echo "date" | install -m 775 /dev/stdin /bin/now
 ---> Running in 95919b575638
Removing intermediate container 95919b575638
 ---> cd1fafd96ef3
Step 3/3 : CMD /bin/now
 ---> Running in 03b5c3ac7265
Removing intermediate container 03b5c3ac7265
 ---> 8f30b527dd29
Successfully built 8f30b527dd29
Successfully tagged temp:latest

$ docker run --rm temp
Thu Nov 12 07:44:24 UTC 2020

$ docker run --rm temp ls -la /bin/now
-rwxrwxr-x    1 root     root             5 Nov 12 07:44 /bin/now

$ docker rmi temp
Untagged: temp:latest
Deleted: sha256:8f30b527dd29203b67c86290b34b0a29d3c98a48134609d0b1e2b89087a7d6e7
Deleted: sha256:cd1fafd96ef3084226c5f98f472e3e08bc9a9f0448cc3e68b6f1c192d12d778a
Deleted: sha256:e58c75acbf953a64d35089cf50e1c5b762601e1cb9d9d1d668e135f23ce1fe86

更新

一位评论者说:

我不明白这与问题有什么关系。

  1. OP在这个问题中的主题是“单个命令创建文件并设置其权限”
  2. OP包括“在Unix(Korn Shell)中执行两个操作的单个命令”

这个主题会出现在Docker用户的Google搜索中。 OP指定了“korn shell”,这意味着要避免bash特定的功能。因为Alpine和许多其他用于容器的最小Linux基础不包括bash,所以排名靠前的答案对他们不起作用。我的答案适用于他们和OP的korn shell。使用Docker演示解决方案意味着任何使用Linux、macOS、Windows或WSL2 in Windows的人都可以通过阅读来自我的机器的转录轻松地在他们的机器上重新创建演示。


1
我不明白这与问题有什么关系。 - xeruf
这个答案确实提供了有用的信息 - 如何创建一个具有给定权限和从stdin中传输的内容的文件。此答案的其他部分仅演示该技术的工作原理,因此也很有用,尽管我认为它可以更清晰地表述。 - Ken Williams
我应该澄清一下 - 当在Alpine(Docker或其他情况)中运行此命令时,install不能保证能够处理设备文件。这太糟糕了,因为它本来是我使用场景的完美解决方案(从echo中传输内容)。 - Ken Williams
@KenWilliams 这样更有意义,但基于macOS man页面/dev/null是一个有效的来源,我仍然感到惊讶。我不再使用Mac,但我会看看是否能找到重现您的问题并找到解决方案的方法。感谢您的反馈。 - Bruno Bronosky
@KenWilliams 这是macOS用户常见的问题:install二进制文件和许多其他核心实用程序(例如grepdatemktemp等)已经从AT&T Unix版本重写为GNU / Linux,并且尽管尝试保留大多数标志的行为,但存在明显的差异。Unix被BSD采用,而在macOS下面的Darwin内核则采用了FreeBSD的原始Unix用户空间的后期版本。 - Ryder
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接