或者,有关强大的文件名处理和在 shell 脚本中传递的其他字符串的介绍性指南。
我写了一个 shell 脚本,它在大多数情况下运行良好。但它在某些输入(例如某些文件名)上窒息。
我遇到了如下问题:
hello world
,它被视为两个单独的文件hello
和world
.\[*?
,它们会被一些文本替换,这实际上是文件的名称。'
(或双引号"
),在那之后事情变得很奇怪。\
分隔符)。这是怎么回事,我该如何解决?
我一直看到引用此链接的答案明确指出“不要解析ls
!” 这让我感到困扰有几个原因:
似乎该链接中的信息已被批量接受,几乎没有问题,尽管我可以在随意阅读中至少挑出一些错误。
该链接中所述的问题似乎也引发了不想找到解决方案的愿望。
从第一段:
...当你要求
[ls]
一个文件列表时,有一个大问题:Unix 允许文件名中的几乎任何字符,包括空格、换行符、逗号、管道符号,以及几乎任何你曾经尝试用作除 NUL 外的分隔符。...ls
用换行符分隔文件名。这很好,直到您的文件名称中包含换行符。并且由于我不知道任何ls
允许您使用 NUL 字符而不是换行符终止文件名的实现,这使我们无法使用ls
.
无赖,对吧?如何以往我们可以处理一个换行符终止的上市数据集可能包含换行符的数据?好吧,如果这个网站上回答问题的人不是每天都做这种事情,我可能会认为我们遇到了麻烦。
事实是,大多数ls
实现实际上提供了一个非常简单的 api 来解析它们的输出,我们一直在做,甚至没有意识到。您不仅可以以 null 结束文件名,还可以以 null 或您可能需要的任何其他任意字符串开头。更重要的是,您可以为每个文件类型分配这些任意字符串。请考虑:
LS_COLORS='lc=\0:rc=:ec=\0\0\0:fi=:di=:' ls -l --color=always | cat -A
total 4$
drwxr-xr-x 1 mikeserv mikeserv 0 Jul 10 01:05 ^@^@^@^@dir^@^@^@/$
-rw-r--r-- 1 mikeserv mikeserv 4 Jul 10 02:18 ^@file1^@^@^@$
-rw-r--r-- 1 mikeserv mikeserv 0 Jul 10 01:08 ^@file2^@^@^@$
-rw-r--r-- 1 mikeserv mikeserv 0 Jul …
Run Code Online (Sandbox Code Playgroud) 我可以写
VAR=$VAR1
VAR=${VAR1}
VAR="$VAR1"
VAR="${VAR1}"
Run Code Online (Sandbox Code Playgroud)
最终结果对我来说似乎都差不多。我为什么要写一个或另一个?这些中的任何一个都不是便携式/ POSIX 吗?
我的印象是,单个参数的最大长度在这里不是问题,而是整个参数数组的总大小加上环境的大小(仅限于ARG_MAX
. 因此,我认为类似以下的事情会成功:
env_size=$(cat /proc/$$/environ | wc -c)
(( arg_size = $(getconf ARG_MAX) - $env_size - 100 ))
/bin/echo $(tr -dc [:alnum:] </dev/urandom | head -c $arg_size) >/dev/null
Run Code Online (Sandbox Code Playgroud)
这- 100
足以解释 shell 和echo
进程中环境大小之间的差异。相反,我收到了错误:
bash: /bin/echo: Argument list too long
Run Code Online (Sandbox Code Playgroud)
玩了一段时间后,我发现最大值小了一个完整的十六进制数量级:
/bin/echo \
$(tr -dc [:alnum:] </dev/urandom | head -c $(($(getconf ARG_MAX)/16-1))) \
>/dev/null
Run Code Online (Sandbox Code Playgroud)
当减一被删除时,错误返回。看似单个参数的最大值实际上是放置在参数数组中字符串末尾的空字节ARG_MAX/16
的-1
帐户。
另一个问题是,当参数重复时,参数数组的总大小可以接近ARG_MAX
,但仍然不完全:
args=( $(tr -dc [:alnum:] </dev/urandom | head -c $(($(getconf ARG_MAX)/16-1))) )
for x in {1..14}; …
Run Code Online (Sandbox Code Playgroud) shell ×3
quoting ×2
shell-script ×2
arguments ×1
bash ×1
echo ×1
kernel ×1
ls ×1
posix ×1
whitespace ×1