Como escapar de barras invertidas em 'sed' dentro de 'find… -exec'?

1

Eu quero mudar uma linha em alguns arquivos em subdiretórios diferentes. Os arquivos sempre terão a extensão .dct e sempre estarão em um subdiretório chamado mod dentro de outro subdiretório do diretório de trabalho (mas há muitos subdiretórios mod , então eu uso find ). Mas as strings que eu quero mudar são diretórios (Windows - > Unix).

Eu posso obter os arquivos relevantes com find . -type f -path '*/mod/*.dct . Eu tentei alterar as linhas relevantes com sed -e 's/cd c:\project\data\/cd \/project\/data\//' $(basename {}) > $(basename {}).mod .

Eu reduzi-o às barras invertidas escapadas sendo o culpado. Isso funciona:

find . -type -f -path '*/mod/*.dct' -execdir sh -c "sed -e 's/c://' $(basename {}) > $(basename {}).mod"

Isso não:

find . -type -f -path '*/mod/*.dct' -execdir sh -c "sed -e 's/c:\//' $(basename {}) > $(basename {}).mod"

Este é o erro

sed: -e expression #1, char 7: unterminated 's' command

A parte char 7 me fez pensar que há algum problema com o escape. Parece que é o caso, mas não sei como resolvê-lo. Por exemplo, isso funciona:

find . -type -f -path '*/mod/*.dct' -execdir sh -c "sed -e 's/c:\//' $(basename {}) > $(basename {}).mod"

Portanto, parece que sed -e 's/c:\///' escapou para "substituir c:\/ por nada" e sed -e 's/c:\//' foi ignorado para "substituir c:\/ por ..." (e isso gera um erro) em vez de "replace c:\ com nada ".

NB: usar -execdir e basename em vez de -exec pode ser um exagero, mas li em algum lugar que era uma boa forma.

    
por Ole 04.11.2017 / 13:47

1 resposta

1

A essência da sua pergunta é como substituir uma barra invertida (por exemplo, \ ) por uma barra (ou seja, / ) chamando sed de find . Para fazer isso, você tem que fazer uma dupla saída das barras invertidas, porque a string será processada duas vezes: uma vez pela invocação de find e, em seguida, uma segunda vez pela invocação de sed . Isso deve fornecer o seguinte:

find . -type f -path '*/mod/*.dct' -execdir sh -c "sed -e 's/cd c:\\project\\data\\/cd \/project\/data\//' $(basename {}) > $(basename {}).mod" \;

Segue uma explicação mais detalhada.

Primeiro, vamos configurar um exemplo um pouco mais simples do seu problema:

# Create a target directory
mkdir -p /tmp/dir1/mod/dir2

# Create a text file containing a backslash
echo '\' > /tmp/dir1/mod/dir2/file.dct

Agora, vamos tentar usar find e sed para substituir essa barra invertida por uma barra:

find /tmp/dir1 -type f -path '*/mod/*.dct' -execdir sh -c "sed -e 's/\/\//' $(basename {})" \;

Isso produz o seguinte erro:

sed: -e expression #1, char 7: unterminated 's' command

Isso porque o comando sed que está sendo executado é o seguinte:

sed -e 's/\/\//' ./file.dct

Você confirma que recebeu o mesmo erro ao executar este comando diretamente, por exemplo:

sed -e 's/\/\//' /tmp/dir1/mod/dir2/file.dct

Você também pode verificar isso executando echo no comando find , por exemplo:

find /tmp/dir1 -type f -path '*/mod/*.dct' -execdir echo "sed -e 's/\/\//' $(basename {})" \;

Para corrigir o comando, nós escapamos duas vezes das barras invertidas:

find . -type f -path '*/mod/*.dct' -execdir sh -c "sed -e 's/\\/\//' $(basename {})" \;

Isso produz o resultado desejado:

/
    
por 04.11.2017 / 14:30