R中system()调用Linux大括号扩展匹配目录时出错的问题排查
我之前也踩过这个坑!问题的核心在于bash的大括号扩展是shell层面的语法,必须由bash亲自解析才能生效,而R的system()函数在某些情况下会跳过shell直接执行命令,导致扩展失败。下面给你几个针对性的解决办法,完全不用重写现有脚本:
1. 确保system()启用shell解析
如果你的脚本里不小心设置了shell=FALSE(这个参数默认在Unix系统下是TRUE,但可能被修改过),那么大括号扩展会直接失效——因为此时R会跳过shell,直接把命令传给系统调用,操作系统只会把/r18_{060..119}当作一个字面路径,自然找不到。
只要在调用system()时显式指定shell=TRUE即可:
system("ls /r18_{060..119}", shell=TRUE)
2. 强制用bash解析命令(最稳妥的方案)
如果不确定system()的shell参数是否被全局修改,或者担心环境变量的问题,可以直接在命令里调用bash来处理扩展,这样不管R的默认设置是什么,都能保证大括号扩展生效:
system("bash -c 'ls /r18_{060..119}'")
这里的bash -c会让bash单独解析引号内的命令,大括号扩展会被正常展开成060到119的目录列表。
3. 检查并设置R的默认shell
有时候R的默认shell可能不是bash(比如某些系统默认是sh),这时候即使shell=TRUE,也会用不支持大括号扩展的shell执行命令。你可以先检查当前shell:
Sys.getenv("SHELL")
如果输出不是/bin/bash,可以在脚本开头设置环境变量,强制R用bash作为默认shell:
Sys.setenv(SHELL="/bin/bash") # 之后正常调用system()即可 system("ls /r18_{060..119}")
为什么手动执行正常,R里不行?
在终端手动输入命令时,是bash直接接收并解析命令,它会先把{060..119}扩展成060 061 ... 119,再执行ls命令。但如果R的system()没有经过bash处理,这个扩展步骤就会被跳过,系统只能去寻找一个名为/r18_{060..119}的路径,当然会报错“无法找到路径”。
内容的提问来源于stack exchange,提问作者Timothy Whitby

