【问题标题】:How to escape $ in a echo command nested inside sed command如何在嵌套在 sed 命令中的 echo 命令中转义 $
【发布时间】:2019-09-26 11:14:15
【问题描述】:

我在makefile 中有一个用于准备存储库的配方,它将所有.sh 文件转换为可执行文件。

在 Ubuntu 18.04 中,以下makefile

SHELL:=/bin/bash

prepare_repo:
    pip install flake8==3.6.0
    rm -f .git/hooks/pre-commit
    flake8 --install-hook git
    git config --bool flake8.strict true

    sed  '/__main__/r'<(\
        echo -e "    import subprocess\n\
    subprocess.check_call(\"find . -name '*.sh'         \n\
       -exec sh -c '                                    \n\
         for f do                                       \n\
           git check-ignore -q  '$f'||                  \n\
           printf '%s\\\n'      '$f'                    \n\
         done                                           \n\
       ' find-sh {} + | xargs git update-index --chmod=+x\", shell=True)"\
    ) -i --  .git/hooks/pre-commit

我加入了pre-commit 事件,因为我想将所有不在.gitignore 文件中的.sh 文件转换为可执行文件。

但问题是,如果我进入.git/hooks/pre-commit,我会找到以下代码

#!/home/fadi/anaconda3/bin/python
import sys

from flake8.main import git

if __name__ == '__main__':
    import subprocess
    subprocess.check_call("find . -name '*.sh'          
       -exec sh -c '                                    
         for f do                                       
           git check-ignore -q  ''||                    
           printf '%s\n'        ''                  
         done                                           
       ' find-sh {} + | xargs git update-index --chmod=+x", shell=True)
    sys.exit(
        git.hook(
            strict=git.config_for('strict'),
            lazy=git.config_for('lazy'),
        )
    )

请注意这段代码是如何对$ 进行转义的。

git check-ignore -q  ''||                    
printf '%s\n'        ''                 

【问题讨论】:

    标签: shell sed escaping echo


    【解决方案1】:

    你在 make 里面用美元逃避美元。

    all:
        # will print empty line
        echo $f
        # will print '$'
        echo $$
    
    prepare_repo:
        ...
        ...
           git check-ignore -q  '$$f'||                  \n\
           printf '%s\\\n'      '$$f'                    \n\
        ...
    

    【讨论】:

      【解决方案2】:

      这可能对你有用(GNU sed & shell):

      cat <<EOF | sed -i -- '/__main__/r /dev/stdin'  .git/hooks/pre-commit        
      import subprocess\n\
          subprocess.check_call(\"find . -name '*.sh'         
              -exec sh -c '                                    
               for f do                                       
                 git check-ignore -q  '$f'||                  
                 printf '%s\\\n'      '$f'                    
               done                                           
             ' find-sh {} + | xargs git update-index --chmod=+x\", shell=True)"
      EOF
      

      使用 cat 和管道而不是 &lt;(...)

      注意" 的引用可能需要调整。

      【讨论】:

      • EOF 似乎不起作用,我将用最终答案更新我的问题,虽然我发现我的解决方案有点难看
      【解决方案3】:

      我终于设法解决了这个问题。

      SHELL:=/bin/bash
      prepare_repo:
          pip install flake8==3.6.0
          rm -f .git/hooks/pre-commit
          flake8 --install-hook git
          git config --bool flake8.strict true
      
          sed  '/__main__/r'<(\
              echo -e "    import subprocess\n\
          subprocess.check_call(\"\"\"find . -path ./pg_data -prune -o -name '*.sh' -exec sh -c ' \n\
              for f do                                        \n\
                git check-ignore -q \"\$$f\" ||               \n\
                printf \"%s\\\n\" \"\$$f\"                    \n\
              done                                            \n\
              ' find-sh {} + | xargs git update-index --chmod=+x\"\"\", shell=True)" \
          ) -i --  .git/hooks/pre-commit
      

      .git/hooks/pre-commit

      以下是由上述配方生成的。

      #!/home/fadi/anaconda3/bin/python
      import sys
      
      from flake8.main import git
      
      if __name__ == '__main__':
          import subprocess
          subprocess.check_call("""find . -path ./pg_data -prune -o -name '*.sh' -exec sh -c '    
          for f do                                        
            git check-ignore -q "$f" ||               
            printf "%s\n" "$f"                    
          done                                            
          ' find-sh {} + | xargs git update-index --chmod=+x""", shell=True)
          sys.exit(
              git.hook(
                  strict=git.config_for('strict'),
                  lazy=git.config_for('lazy'),
              )
          )
      

      【讨论】:

        猜你喜欢
        • 2021-07-22
        • 1970-01-01
        • 2021-06-26
        • 2013-04-05
        • 2015-12-02
        • 2013-07-08
        • 1970-01-01
        • 2014-12-16
        • 2017-10-12
        相关资源
        最近更新 更多