处理带转义引号的Spark提交配置字符串的工具选型问询
处理Spark Submit配置字符串的正确姿势
你遇到的问题本质上是解析带引号和转义的shell风格命令行参数,而不是简单的空格分割——这也是为什么words和硬编码正则都没法通用的原因。这类场景下,最合适的工具要么是专门处理shell参数拆分的现成库,要么是自己实现一个轻量的状态机解析逻辑,下面具体说明:
一、用现成的Haskell库:shellwords
Haskell的shellwords包专门用来解析shell风格的命令行参数,能正确识别引号包裹的内容、转义字符,完美适配你的场景。
步骤1:安装依赖
首先在你的项目中添加shellwords依赖(比如在cabal文件里加上shellwords >= 0.1.2),或者用cabal install shellwords单独安装。
步骤2:实现函数
用shellSplit代替words,就能正确拆分带引号的参数,之后再插入--conf:
import Data.List (intercalate) import System.ShellWords (shellSplit) concatConf :: String -> String concatConf conf = case shellSplit conf of [] -> "" parts -> " --conf " ++ intercalate " --conf " parts
测试一下你提到的复杂场景:
-- 输入带引号的配置 let input = "spark.yarn.memoryOverhead=3g spark.executor.extraJavaOptions=\"-verbose:gc -XX:+UseSerialGC -XX:+PrintGCDetails -XX:+PrintAdaptiveSizePolicy\" spark.default.parallelism=1000 spark.yarn.executor.memoryOverhead=2000" concatConf input
输出会是:
" --conf spark.yarn.memoryOverhead=3g --conf spark.executor.extraJavaOptions=\"-verbose:gc -XX:+UseSerialGC -XX:+PrintGCDetails -XX:+PrintAdaptiveSizePolicy\" --conf spark.default.parallelism=1000 --conf spark.yarn.executor.memoryOverhead=2000"
完全符合预期,不管是spark.driver.extraJavaOptions还是其他带空格的参数都能正确处理。
二、自己实现轻量状态机解析(如果不想依赖额外库)
如果不想引入外部依赖,你可以写一个简单的状态机,跟踪当前是否处于引号内,以此判断空格是否作为分隔符:
import Data.List (intercalate) -- 状态:是否处于引号中 data ParseState = InQuote | OutOfQuote deriving (Eq) splitShellArgs :: String -> [String] splitShellArgs = reverse . fst . foldl parseChar ([], OutOfQuote, "") where parseChar (acc, state, current) c = case (state, c) of -- 遇到双引号,切换状态 (OutOfQuote, '"') -> (acc, InQuote, current) (InQuote, '"') -> (acc, OutOfQuote, current) -- 处于引号外时,空格作为分隔符,把当前内容加入列表 (OutOfQuote, ' ') -> if null current then (acc, OutOfQuote, "") else (current:acc, OutOfQuote, "") -- 其他情况,把字符加入当前内容 _ -> (acc, state, current ++ [c]) -- 处理最后一个未完成的参数 parseChar (acc, _, current) _ = (if null current then acc else current:acc, OutOfQuote, "") concatConf :: String -> String concatConf conf = case splitShellArgs conf of [] -> "" parts -> " --conf " ++ intercalate " --conf " parts
这个实现会正确识别引号内的空格,不会拆分带引号的参数,同样能处理你遇到的所有场景。
为什么正则和words不行?
words会把所有空格都当作分隔符,不管是否在引号内,直接拆分带空格的参数。- 正则只能针对特定的参数名(比如
extraJavaOptions)写规则,没法覆盖所有可能的带空格参数,扩展性极差,遇到新的参数名就失效。
而shell参数解析逻辑是通用的,不管参数是什么名字,只要符合shell的引号转义规则,都能正确处理——这才是适配你需求的正确方向。
内容的提问来源于stack exchange,提问作者user4601931
相关产品推荐
相关产品推荐

