Corretamente escapando de barra no script bash para uso com sed

14

Estou tentando determinar o tamanho dos arquivos que seriam copiados recentemente ao sincronizar duas pastas executando o rsync no modo dry e, em seguida, somando os tamanhos dos arquivos listados na saída do rsync.

Atualmente, estou preso ao prefixar os arquivos por sua pasta pai. Eu descobri como prefixar linhas usando sed e como escapar usando sed, mas estou tendo problemas combinando esses dois.

Isto é o quão longe eu cheguei:

source="/my/source/folder/"
target="/my/target/folder/"
escaped='echo "$source" | sed -e 's/[\/&]/\//g''
du 'rsync -ahnv $source $target | tail -n +2 | head -n -3 | sed "s/^/$escaped/"' | awk '{i+=$1} END {print i}'

Esta é a saída que recebo do bash -x myscript.sh

+ source=/my/source/folder/
+ target=/my/target/folder
++ echo /my/source/folder/
++ sed -e 's/[\/&]/\//g'
+ escaped=/my/source/folder/
+ awk '{i+=$1} END {print i}'
++ rsync -ahnv /my/source/folder/ /my/target/folder/
++ sed 's/^//my/source/folder//'
++ head -n -3
++ tail -n +2
sed: -e expression #1, char 8: unknown option to 's'
+ du
80268

Qualquer ideia de como escapar adequadamente seria muito apreciada.

    
por user331839 09.06.2014 / 21:55

2 respostas

27

Você não precisa se preocupar em escapar do / . Você pode usar qualquer outro caractere único no lugar dele. Por exemplo:

echo 'foobar' | sed -e 's#foo#bar#'

fornece a saída

barbar
    
por 09.06.2014 / 22:14
0

Se você está tentando calcular os dados, provavelmente vai querer pular todos os subdiretórios possíveis. Isso pode não ser aplicável, mas é sempre melhor evitar qualquer estranheza. Aqui está o meu diretório de origem. Esses arquivos foram todos criados com toque, então eles ocupam 0 espaço.

$ find source
source
source/5832
source/5832/5832_1.png
source/5832/5832_2.png
source/5831
source/5831/5831_1.png
source/5830
source/5830/5830_3.png
source/5830/5830_1.png
source/5830/5830_2.png

Você não deve precisar escapar em qualquer lugar perto do que está fazendo. O bloco sed aqui fará o seguinte: 1d; excluir a primeira linha de 'envio de lista de arquivos incrementais'
/ ^ $ /, $ d; exclua a linha em branco que significa o final da lista de arquivos e tudo depois dela.
// $ / d excluir qualquer linha que termine em '/', que seriam os diretórios Note que você pode escapar das barras com barras invertidas (para responder à pergunta atual).

$ du $(rsync -ahnv source target | sed '1d;/^$/,$d;/\/$/d')
0   source/5830/5830_1.png
0   source/5830/5830_2.png
0   source/5830/5830_3.png
0   source/5831/5831_1.png
0   source/5832/5832_1.png
0   source/5832/5832_2.png

E para pontos de bônus extras, você pode até calcular os resultados:

$ du -s $(rsync -ahnv source target | sed '1d;/^$/,$d;/\/$/d') | awk '{x+=$1;print $0} END {print "sum: "x}'
0   source/5830/5830_1.png
0   source/5830/5830_2.png
0   source/5830/5830_3.png
0   source/5831/5831_1.png
0   source/5832/5832_1.png
0   source/5832/5832_2.png
sum: 0

Se você estiver fazendo isso com o diretório já totalmente sincronizado, ele retornará resultados engraçados:

76  .
sum: 76
    
por 09.06.2014 / 23:01