String 生成包含变量值的bash字符串,该变量值用单引号括起来

String 生成包含变量值的bash字符串,该变量值用单引号括起来,string,bash,variables,quote,String,Bash,Variables,Quote,我做了一个噩梦,因为这是最琐碎的任务 我的最终目标是从bash脚本发出以下命令: sqlite3 my\u db.db'。读取my\u file.sql' 这里有两个陷阱: 1.单引号是必须的,不能用双引号代替 2. my_file.sql是一个只有在运行时才知道的变量 所以我需要的是一种让bash构建一个字符串的方法,该字符串一方面包含一个变量值,另一方面该值应该用单引号括起来 我还更喜欢不依赖额外工具(如AWK、Perl等)的解决方案。如果真的有必要的话,也许是塞德 谢谢 谢谢乔纳森和纳尔

我做了一个噩梦,因为这是最琐碎的任务

我的最终目标是从bash脚本发出以下命令:
sqlite3 my\u db.db'。读取my\u file.sql'

这里有两个陷阱:
1.单引号是必须的,不能用双引号代替
2.
my_file.sql
是一个只有在运行时才知道的变量

所以我需要的是一种让bash构建一个字符串的方法,该字符串一方面包含一个变量值,另一方面该值应该用单引号括起来

我还更喜欢不依赖额外工具(如AWK、Perl等)的解决方案。如果真的有必要的话,也许是塞德

谢谢


谢谢乔纳森和纳尔逊

我尝试了这三个建议,但都失败了。
为了简单起见,我将问题归结为以下几点:

  • 我写了以下脚本(tst.sh):
    #/bin/bash

    文件=/tmp/1

    ls““$file””

    ls\'$file\'

    ls“$file”

  • 然后我使用以下命令:
    $touch/tmp/1

    $ls'/tmp/1'

    /tmp/1

    $。/tst.sh

    “/tmp/1”:没有这样的文件或目录
    
    “/tmp/1”:没有这样的文件或目录
    
    “/tmp/1”:没有这样的文件或目录

  • 似乎确实添加了引号,但生成的命令与手动输入的命令不同

    有什么想法吗?

    你可以做如下事情:

    VAR=my_file.sql
    VAR2="'.read $VAR'"
    sqlite3 my_db.db $VAR2
    

    这将实现您希望执行的操作(为程序获取单引号),但它使用双引号:

    sqlite3 my_db.db "'".read" "my_file.sql"'"
    
    避免双引号,您可以编写:

    sqlite3 my_db.db \'.read\ my_file.sql\'
    
    对于这两个参数,
    sqlite3
    将第二个参数视为包含以下内容的字符串:

    '.read my_file.sql'
    
    如果文件名位于变量(
    file=my_file.sql
    )中,则:

    如果文件名包含空格,这些符号很容易混淆

    然而,我不认为这是你真正想要的。禁止双引号的规定令人费解,单引号的要求也同样令人费解。

    单引号不是强制性的。以下所有命令都使用完全相同的参数运行sqlite3:

    sqlite3 my_db.db '.read my_file.sql'
    sqlite3 my_db.db ".read my_file.sql"
    sqlite3 my_db.db .read\ my_file.sql
    sqlfile="my_file.sql"
    sqlite3 my_db.db ".read $sqlfile"
    
    在所有情况下,在将参数传递给sqlite3之前,都会解析并删除引号(/escape)。这就是你想要的。您希望sqlite3获得两个参数:
    my_db.db
    。请阅读my_file.sql
    。您不希望sqlite3看到命令周围的引号——这相当于:

    $ sqlite3 my_db.db
    SQLite version 3.7.7 2011-06-25 16:35:41
    Enter ".help" for instructions
    Enter SQL statements terminated with a ";"
    sqlite> '.read my_file.sql'
       ...>
    
    …正如您所看到的,这让sqlite3感到困惑


    顺便说一句,这与ls示例中的问题相同:您将单引号作为参数的一部分传递给ls,因此它正在查找名称中包含单引号的文件,而没有找到它。您希望shell删除引号,而不是将其作为参数的一部分传递给命令。

    好的,问题解决了

    缺少的只是在行之前添加一个小的“eval”命令。
    因此,在我给出的简单示例脚本中,更改:
    ls“$file”
    to:
    eval ls“$file”

    完成了任务


    感谢所有回复者:-)

    user1860085,如果您查看了sqlite3命令的文档,并且您将了解shell如何处理引号和空格,您可能会得出结论,您希望在案例中使用双引号

    但如果您真的想要单引号,以下是解决方案:

    eval sqlite3 my_db.db \'.read $VARIABLE\'
    
    飞行中的哪个将更改为:

    sqlite3 my_db.db '.read my_file.sql'
    

    但是我不明白你为什么想要它…

    为什么单引号是必须的?这应该是单引号中的一个参数还是两个参数,一个以单引号开始,另一个以单引号结束。谢谢戈登-这是我不知道的重要信息。不过,我的问题比sqlite3语法更广泛,这在主题中可以看到。我相信我的最后一个答案在很多其他情况下都会对其他人有所帮助。@user1860085:深呼吸,理解这里的一些评论者反复试图解释的内容:你在解决错误的问题,你需要理解shell的引用机制。对于这个清晰的答案+1。啊,不!eval的主要目的是创建无法理解的bug。如果你确切知道自己在做什么,它可以安全地使用,但这不是那种情况。哈哈,对不起,无意冒犯;-)您能否详细说明您提到的eval的问题性质,以及它将如何影响我的解决方案(似乎正在工作…)?它显示了如何去除两层引号,但最终结果与
    ls“$file”
    完全相同。在需要引号的情况下,它与ls“$file”并不相同。例如,在我最初的示例中,它在失败时工作。您在这里所做的是在命令周围添加单引号,然后使用
    eval
    删除它们。说真的,这是
    eval
    在这里做的唯一一件事。如果它还做了什么,那就是坏事。在这种特殊情况下,
    eval
    只会在文件名包含单引号时引起问题(在这种情况下,sqlite3无论如何都会有问题),但您最好首先避免这个问题。是什么让你觉得你需要单引号?我敢肯定,您在使用
    sqlite3 my_db.db.read$file“
    时遇到的任何问题都不是因为缺少单引号。也不是因为没有变量
    sqlite3 my_db.db“'。read my_file.sql'
    但我怀疑这是否真的是解决方案,尽管这正是OP所要求的。
    sqlite3 my_db.db '.read my_file.sql'