使用sed删除前导空格的多行bash:命令参数中错误保留的引号

使用sed删除前导空格的多行bash:命令参数中错误保留的引号,bash,heredoc,sshfs,Bash,Heredoc,Sshfs,我正在运行这段代码: annotate-output $((sed -E 's/^[ ]+//;' <<____COMMAND sshfs foo_user@fooserver.com:/sftp_folder /var/sshfs.sandbox/server.com -o user=foo_user ,reconnect ,ServerAliveInterval=15 ,ServerAliveCountMax=3 ____CO

我正在运行这段代码:

annotate-output $((sed -E 's/^[ ]+//;'  <<____COMMAND

sshfs 
foo_user@fooserver.com:/sftp_folder 
  /var/sshfs.sandbox/server.com 
  -o 
    user=foo_user
    ,reconnect
    ,ServerAliveInterval=15
    ,ServerAliveCountMax=3

____COMMAND
) | sed -E -e ':a;N;$!ba;s/\n//g')
对于必须在没有中间空白的情况下连接的选项,没有尾随空格:

user=foo_user
,reconnect
,ServerAliveInterval=15
,ServerAliveCountMax=3
如果我在任何地方都没有引号或双引号,它可以正常工作。如果我运行这个:

annotate-output $((sed -E 's/^[ ]+//;'  <<____COMMAND

sshfs 
foo_user@fooserver.com:/sftp_folder 
  "/var/sshfs.sandbox/server.com"
  -o 
    user=foo_user
    ,reconnect
    ,ServerAliveInterval=15
    ,ServerAliveCountMax=3

____COMMAND
) | sed -E -e ':a;N;$!ba;s/\n//g')
看起来引号是作为参数的一部分传递给sshfs的。为什么?

编辑1 20170418 0739[注意这现在是a]: 我现在明白了为什么引用被保留下来了-参见

我模仿了我的解决方案。我需要应用sed两次,一次用于前导空间,另一次用于EOL,这就是我最终使用这些理解的原因。 PS:我有前导空格,而不是前导制表符,因此这种方法实际上是有效的 解释为什么另一种方法不能 无引号的扩展将执行以下解析步骤,并且仅执行以下解析步骤:

根据IFS中的字符将字符串拆分为多个不同的单词 Glob扩展将任何看起来像Glob表达式的单词替换为与该表达式匹配的名称列表。 就这样。无引号、无引号删除、无参数替换等。如果引号没有被解析为语法,它们将导致解析为单个单词的变量就不会以这种方式解析;在不删除引号的情况下,这些引号在被调用的命令中以文本数据的形式出现

有关详细讨论,请参阅。

使用eval 下面是您想要的-删除前导空格而不是尾随空格,并将herdoc内容合并到单个命令中。在命令末尾保留一个尾随的换行符不需要费尽心思:eval true即使在换行符文本中没有true结尾,也能很好地工作

eval "$(
  { sed -E -e 's/^[ ]+//;' -e ':a;N;$!ba;s/\n//g' | tr -d '\n'; } <<'____COMMAND'
sshfs 
foo_user@fooserver.com:/sftp_folder 
  /var/sshfs.sandbox/server.com 
  -o 
    user=foo_user
    ,reconnect
    ,ServerAliveInterval=15
    ,ServerAliveCountMax=3
____COMMAND
)"
需要注意的一些事项:

herdoc __;命令中的符号被引用。这确保了扩展只在调用eval之后发生,而不是在扩展herdoc内容本身时发生。 可以使用-e调用将多个命令传递给单个sed调用。 但是不要。认真地
给尾随空格赋予语义意义是一种很容易让其他阅读代码的人感到困惑的方法。正如制表符与空间的问题在PEP-8仅在空格上标准化之前,几代开发人员都在使用Makefiles或Python一样,在语义上有意义的区分是尾随空格还是无尾随空格会让阅读代码的人严重困惑,并且会导致与自动格式验证的冲突,例如在当前发布的Git的当前版本中包含的功能,当将来任何行包含尾随空白时,警告。

详细地在.BTW中-您会考虑重新命名吗?我如何能够在没有反斜杠的情况下,分割包含多行的引号的命令?适当的更改?两个注意事项:1-如果您最初问的问题有答案,而您现在有一个新的/不同的问题,则该新的/不同的问题应作为单独的问题提问-这样,对原始问题的编辑不会使该答案无效。2-更多地描述你想要什么以及为什么想要它会很有帮助。在bash中实现多行可能对您来说很有用,但我向您保证,这对每个人来说并不意味着相同的事情。呃,请注意三点:另外,当您说您不想要基于字符串操作的解决方案时-字符串操作正是您最初的sed方法,所以现在还不清楚这句话的意思,我已经编辑过了。请注意,我希望能够在一个位置输入新的、缩进的命令。。只有一个地方才是关键。您的解决方案拆分了该命令。当引用无引号的扩展时,您是指无引号的here文档吗?或者你指的是命令替换的扩展?那将是后者。好的,谢谢你的解释,这是有意义的。但我对您的解决方案有一个问题:它会拆分命令。我知道我可以通过字符串操作实现我想要的——但我不想那样。我想要一个通用的页眉/页脚,我可以粘贴到任何脚本中,只要键入我不必担心缩进的情况下会键入的命令即可。难道没有一种方法可以让它这样工作吗?它在这里被拆分的唯一原因是因为你有逗号分隔的选项,你想神奇地将它们合并成一个字符串,而不是像其他任何东西一样被分隔成不同的参数。否则,就不需要区分选项,也不需要修改IFS。好吧,我理解这一点,但肯定不是神奇的,考虑到我发布的sed解决方案确实存在报价问题,因为您提到的未报价的扩展问题;但这是另一个问题,如果不需要引用命令,我可以使用它。只要在你需要的时候,在这行的末尾加上空格就行了。谢谢你的支持
洞察力。但读者怎么会感到困惑呢?以上命令的另一种解释是什么?没有一个在一行中折叠该命令的人无论如何都必须手动折叠前导空格,此时是否有尾随空格的问题变得无关紧要。附言:我再次决定:我非常感谢你的评论,但我想了解实践中的区别。我明白git警告的意义——这本身就是一个很好的理由。但就这些吗?实际上有什么区别?但我现在明白了为什么您提出的第一个解决方案使用了一种不同的方法(在单独的语句中定义)来连接参数:如果不使尾随空格变得重要,就无法一次性输入。如果只在某些行上删除前导空格,那么结果将比按照您所做的方式定义和组合数组更麻烦。另一个想法。我可以使用尾随的反斜杠,使尾随的空格可读吗?我已经用python做过了,并且已经习惯了。这将如何影响您的sed/tr命令?这不起作用。前导空格转换为如下单个空格:,reconnect,ServerAliveInterval=15,ServerAliveCountMax=31在我的本地系统上运行命令时引用set-x日志直接从问题中复制和粘贴:++sshfs foo_user@fooserver.com:/sftp_folder/var/sshfs.sandbox/server.com-o user=foo_user,重新连接,ServerAliveInterval=15,ServerAliveCountMax=3。逗号前面没有空格。
fuse: bad mount point `"/var/sshfs.sandbox/server.com"': No such file or directory
IFS=,  # cause "${array[*]}" to combine all items with commas

options=(
  user=foo_user           # can put a comment here if you like
  reconnect               # or here
  ServerAliveInterval=15  # or so forth
  ServerAliveCountMax=3
)

sshfs_cmd=(
  sshfs 
  foo_user@fooserver.com:/sftp_folder 
    /var/sshfs.sandbox/server.com
      -o "${options[*]}"
)

"${sshfs_cmd[@]}"
eval "$(
  { sed -E -e 's/^[ ]+//;' -e ':a;N;$!ba;s/\n//g' | tr -d '\n'; } <<'____COMMAND'
sshfs 
foo_user@fooserver.com:/sftp_folder 
  /var/sshfs.sandbox/server.com 
  -o 
    user=foo_user
    ,reconnect
    ,ServerAliveInterval=15
    ,ServerAliveCountMax=3
____COMMAND
)"