为什么cat、grep等命令无法理解减号开头的文件?

Nic*_*ick 5 command-line shell bash shell-script

如果我有一个名称以单个或多个减号开头的文件,例如--1它不能用作许多命令的参数。即使我跑

cat --1
Run Code Online (Sandbox Code Playgroud)

我收到无法识别的选项错误消息,而不是文件内容:

cat: unrecognized option '--1'
Run Code Online (Sandbox Code Playgroud)

当我输入时出现相同的效果

cat "--1"
cat '--1'
cat \-\-1
Run Code Online (Sandbox Code Playgroud)

没有任何效果。以“-”开头的文件在文件系统中并不违法,但在 cli 和脚本中使用它们是相当困难的。好的,以防万一cat或者grep我可以使用

cat <--1
Run Code Online (Sandbox Code Playgroud)

这会起作用,但是

rm --1
Run Code Online (Sandbox Code Playgroud)

也不起作用,并且很难用其他命令替换此命令。毕竟很不舒服。是否有与不使用此类文件名不同的通用解决方法?

顺便说一句,如果 name file 是单个-并且所有大多数命令都会将其理解为stdin,不是吗?

并且很难不使用这样的文件名,因为我也无法使用mv命令在脚本中重命名它们。

les*_*ana 18

约定是所有以 a 开头的-都是一个选项。这与以-. 为了解决这个问题,大多数命令都将其--视为选项结束标记。之后的所有内容--都不会被识别为选项,而是会从字面上理解为文件名。

例如

cat -- --1
Run Code Online (Sandbox Code Playgroud)

或者

rm -rf -- --1
Run Code Online (Sandbox Code Playgroud)

另一种方法是用路径限定文件名。

例如

cat ./--1
Run Code Online (Sandbox Code Playgroud)

甚至

cat /home/username/foo/--1
Run Code Online (Sandbox Code Playgroud)

最好永远不要创建以-. 文件名可能包含各种字符,包括换行符,但仅仅因为它是可能的并不意味着您必须这样做。

回答您的问题:为什么 cat、grep 和其他命令无法理解以减号开头的文件?因为命令行只是一个字符串。shell 会进行一些文件名扩展、一些单词拆分和一些变量替换,但最终程序会收到一个字符串数组。

如何将表示选项的字符串与表示文件名的字符串分开?通过一些哨兵字符。unix/linux 世界中的约定是使用-作为标记字符。所有以 a 开头的-都是一个选项。嗯,几乎所有的东西。选项的参数也可能以 开头-,但这是单个程序的详细信息。

并非每个程序都符合此约定。可以说最流行的例子是dd

dd if=/dev/random of=whatfreespace
Run Code Online (Sandbox Code Playgroud)

dd识别文件名,因为它们出现在=符号之后。

大多数(如果不是全部)GNU 程序都符合 GNU getopt 约定:短选项以-1 个字符开头,长选项以 开头--并且至少是两个字符。--单独标记选项的结尾,并且该标记之后的所有字符串都不会被识别为选项。有关更多详细信息,请阅读GNU libc 手册中的程序参数语法约定

仅部分符合 GNU 约定的程序的一个示例是find

find -not -name porn -delete
Run Code Online (Sandbox Code Playgroud)

虽然find用于-区分期权和非期权,但长期权和短期权没有区别。它确实识别--为选项的结束。每个程序都可以定义自己的方式来识别选项和文件名以及其他任何内容。

-单个-字符解释为 stdin 的约定也正是如此,即在字符串数组中遇到单个字符时如何解释单个字符的约定。


cho*_*oba 5

任何以破折号开头的东西都被认为是一种选择。您可以在文件名前面加上路径,使其看起来不像一个选项:

cat ./--filename
Run Code Online (Sandbox Code Playgroud)