bash字符串引用

yor*_*007 2 bash

我似乎陷入了矛盾的境地.我有一个长字符串存储在一个变量中,$abstract如下所示:

abstract='test1 and "test2"'
Run Code Online (Sandbox Code Playgroud)

你看到字符串中有一个引号,我想把这个字符串作为一个参数发送到一个命令,我尝试了以下命令:

command_name "$abstract"
Run Code Online (Sandbox Code Playgroud)

在变量替换之后,它变成:command_name test1 and "test2".如果我尝试:

command_name \"$abstract\"
Run Code Online (Sandbox Code Playgroud)

它变成:command_name "test1 and "test2"".两者都不是我想要的.谁能告诉我如何实现我的目标?

rob*_*off 8

你的第一次尝试是正确的:

command_name "$abstract"
Run Code Online (Sandbox Code Playgroud)

command_name用一个参数执行,test1 and "test2".例如:

:; mkdir empty
:; cd empty
:; abstract='test1 and "test2"'
:; touch "$abstract"
:; ls -l
total 0
-rw-r--r--  1 mayoff  wheel  0 Mar  2 21:26 test1 and "test2"
Run Code Online (Sandbox Code Playgroud)

您可以看到touch只创建了一个文件,并且它已命名test1 and "test2".

编辑

因此,根据您的注释,您实际上希望将shell变量插入到SQL语句中以将命令行传递给sqlite3.

首先,您应该知道"在SQLite3中引用字符串是危险的.它允许作为常规规则的例外,如"SQLite关键字"文档中所述,该文档还说"SQLite的未来版本可能会更改以引发错误,而不是接受上述异常所涵盖的格式错误的语句."

所以,如果我们按照预期使用单引号,你想执行这个:

sqlite3 test.db "insert into test values('$abstract')"
Run Code Online (Sandbox Code Playgroud)

当然,这适用于您给出的示例值$abstract.

让我们改为更具挑战性的版本$abstract:

abstract="'test' and \"test2\""
Run Code Online (Sandbox Code Playgroud)

为了解决这个问题,我们需要在SQLite看到之前引用单引号.在SQLite3字符串中,一行中的两个单引号表示一个单引号.也就是说,我们想运行这个SQLite3命令:

insert into test values('''test'' and "test2"')
Run Code Online (Sandbox Code Playgroud)

无论如何,bash实际上有一个方便的方法.在bash,你可以说${variable//PATTERN/STRING},和bash将扩大,为的值$variable,但它将替换的每个实例都PATTERNSTRING在扩张.我们可以用它来$abstract用两个单引号替换每个单引号.但是单引号在出现时是狂妄的PATTERN,所以我们必须用反斜杠引用那里的单引号.但是我们没有引用替换中的单引号STRING.哇,这让人感到困惑,不是吗?

无论如何,你正在寻找的神奇咒语是这样的:

sqlite3 test.db "insert into test values('${abstract//\'/''}')"
Run Code Online (Sandbox Code Playgroud)

我们可以用touch以下方法测试:

:; mkdir empty
:; cd empty
:; touch sqlite3 test.db "insert into test values('${abstract//\'/''}')"
:; ls -l
total 0
-rw-r--r--  1 mayoff  wheel  0 Mar  3 15:01 insert into test values('''test'' and "test2"')
-rw-r--r--  1 mayoff  wheel  0 Mar  3 15:01 sqlite3
-rw-r--r--  1 mayoff  wheel  0 Mar  3 15:01 test.db
Run Code Online (Sandbox Code Playgroud)

或者我们当然可以用SQLite测试它:

:; rm -f test.db
:; sqlite3 test.db 'create table test (x)'
:; sqlite3 test.db "insert into test values('${abstract//\'/''}')"
:; sqlite3 test.db 'select * from test'
'test' and "test2"
Run Code Online (Sandbox Code Playgroud)