1

被引用时,我有以下代码:我怎样才能正确地逃脱bash的变量以各种方式

set -o xtrace 
openDirectory() 
{ 
    lxterminal --command="zsh -c 'cd "$1"; zsh -i' " 
} 

# Handle argument. 
if [ "[email protected]" ] 
then 
    openDirectory ~/Projects/Clients/"@1" 
    cd $1 
fi 

如果传入的参数空间,就会失败。

lxterminal '--command=zsh -c '\''cd /home/chris/Projects/Clients/Test' - 'Space; zsh -i'\'' ' 
cd Test - Space 
cd: too many arguments 

我该如何正确地逃避这个?用bash之类的东西可以做到这一点吗?

+2

为什么不使用'lxterminal'的'--working-directory'参数,而不是'cd' +转义地狱?例如'lxterminal --working-directory“$ 1”--command =“zsh -i”' – jm666

+0

感谢您的解决方法! –

+1

我认为你的意思是'$ 1'而不是'@ 1'。检查是否传递参数的正确方法是使用'if [$#-gt 0]; '。 '“$ @”'会扩展为多个参数,这可能会导致'['失败。 – chepner

回答

3

假设封闭的外壳确实是bash的(因为这个问题被标记),您可以使用printf -v varname %q "$var"存储的var值到名为varname变量的安全引用实例,因为这样的:

openDirectory() 
{ 
    local cd_cmd cmd 
    printf -v cd_cmd '%q ' cd "$1" 
    printf -v cmd '%q ' zsh -c "$cd_cmd && zsh -i" 
    lxterminal --command="$cmd" 
} 

printf '%q'评估为给定字符串的一个版本,当'由bash(或具有等效语义的任何shell)编辑时,将评估为原始文字值。

要解释为什么是这样做的方式:

  • 在上面,在代码中包含的所有引号字符本身是语法而不是字面:我们根据printf %q所有报价并逃脱。这是一种最佳实践方法:使用文字引号意味着正在生成的数据内的文字能够转义这些引号。
  • 通过shell引用运行shell指令(如&&)将使它们成为文字数据。因此,我们想要&&是文字数据而不是语法,当我们将它作为参数传递给-c时,而不是由远程shell处理时的文字数据 - 这就是为什么它仅存在于最后报价通过。
+0

只需注意'openDirecty()“〜”'''不会扩展到用户的主目录。必须指定'openDirectory〜'。 –

+0

正确。引用是每个字符,所以你可以使用空格“'编写'openDirectory〜/”某个名字。 –

2

即使一个很好的建议是在意见中提出,为应对这样的问题,你可以这样写的一般方法:

set -o xtrace 
openDirectory() 
{ 
    local safe_path 
    printf -v safe_path "%q" "$1" 
    lxterminal --command="zsh -c 'cd $safe_path; zsh -i' " 
} 

对于一个更好的方式来准备要传递的命令参见lxterminal,请参阅CharlesDuffy的回答。

至于你的代码的其余部分,我可能会使用以下方法:

# Handle argument. 
if 
    [ -d "$1" ] 
then 
    openDirectory ~/Projects/Clients/"@1" 
    cd "$1" 
fi 

使用"[email protected]"因为如果条件可以产生出0(真),如果参数1存在,但是是空的执行体(空字符串),但后面的参数不是。我认为这不是你想要的。

我不确定“@ 1”是否是打字错误,或者是否确实意味着“Projects/Clients”目录中名为“@ 1”的目录。但当然应该引用参数cd

+0

您没有正确引用参数扩展。它应该是'--command =“zsh -c'cd \”$ 1 \“; zsh -i'”'。 – chepner

+0

@chepner不太清楚为什么我错过了这一点,可能是太过专注于添加缺少的引号,并保持原样。谢谢。 – Fred

+0

这是越野车 - 安全漏洞级越野车 - 就这样。如果你在'$ 1'中传递的目录名包含'$(rm -rf〜)'?这将用双引号扩展。或者'$(rm -rf〜)'$(rm -rf〜)'' - 如果用单引号替换双引号,它仍然会被扩展。 –