Как экранировать $ в команде echo, вложенной в команду sed - PullRequest
0 голосов
/ 26 сентября 2019

У меня есть рецепт в 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, потому что хочу преобразовать все .sh файлы, которые не находятся в файле .gitignore, висполняемый.

Проблема, однако, если я зайду в .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'        ''                 

Ответы [ 3 ]

2 голосов
/ 26 сентября 2019

Вы избегаете доллар с долларом внутри make.

all:
    # will print empty line
    echo $f
    # will print '$'
    echo $$

prepare_repo:
    ...
    ...
       git check-ignore -q  '$$f'||                  \n\
       printf '%s\\\n'      '$$f'                    \n\
    ...
1 голос
/ 26 сентября 2019

Это может сработать для вас (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 и pipe вместо <(...)

NB. Цитирование "может потребоваться регулировка.

0 голосов
/ 26 сентября 2019

Мне наконец удалось решить проблему.

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'),
        )
    )
...