为什么cat、grep等命令无法识别以减号开头的文件?

为什么cat、grep等命令无法识别以减号开头的文件?

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

cat --1

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

cat: unrecognized option '--1'

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

cat "--1"
cat '--1'
cat \-\-1

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

cat <--1

这会起作用,但是

rm --1

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

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

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

答案1

惯例是所有以 a 开头的-都是一个选项。这与以 . 开头的文件名冲突-。为了解决这个问题,大多数命令都将其识别--为选项结束标记。后面的所有内容--都不会被识别为选项,而是按字面意思视为文件名。

例如

cat -- --1

或者

rm -rf -- --1

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

例如

cat ./--1

甚至

cat /home/username/foo/--1

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

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

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

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

dd if=/dev/random of=whatfreespace

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

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

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

find -not -name porn -delete

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

将单个字符解释为 stdin 的约定也只是在字符串数组中遇到-单个字符时如何解释该字符的约定。-

答案2

任何以破折号开头的内容都被视为一个选项。您可以在文件名前面添加路径,使其看起来不像一个选项:

cat ./--filename

答案3

使用cat -- --filename指示停止寻找任何选项。这种方法存在潜在问题,因为第三方应用程序不知道如何处理短划线文件名。然而 POSIX 二进制文件等cp, rm, cat知道如何处理这些破折号

答案4

更一般地说,它是:

cat $options_and_or_file_patterns_or_stdin_if_dash

cat "$option_or_file_or_stdin_if_dash"

cat -- "$file_or_stdin_if_dash"

cat < "$file"

cat - < "$file" # same as above

相关内容