Escapar corretamente da barra invertida no script bash para uso com o sed

14

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

Atualmente, eu estou preso em prefixar os arquivos pela pasta pai. Descobri como prefixar linhas usando sed e como escapar usando sed, mas estou tendo problemas para combinar essas duas.

Foi assim que 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 idéia sobre como escapar adequadamente seria muito apreciada.

user331839
fonte

Respostas:

28

Você realmente não precisa se preocupar em escapar do /. No manual GNUsed :

Os /caracteres podem ser substituídos uniformemente por qualquer outro caractere único em qualquer scomando.

Por exemplo:

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

dá a saída

barbar
jjlin
fonte
4
Esta deve ser a primeira coisa na página de manual do sed
Clearer
Qualquer como em 'any' *?
Ujjwal Singh
0

Se você estiver tentando calcular os dados, provavelmente desejará 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. Todos esses arquivos foram criados com o touch, e 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 precisa escapar nem de perto do que está fazendo. O bloco sed aqui fará o seguinte:
1d; exclua a primeira linha de 'enviando lista de arquivos incrementais'
/ ^ $ /, $ d; exclua a linha em branco que significa o fim da lista de arquivos e tudo o que está depois dela.
// $ / d exclui qualquer linha que termina em '/', que seria o diretório
Observe que você pode escapar das barras com barras invertidas (para responder à pergunta real).

$ 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 ganhar pontos extras, você pode até contar 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
Nomes falsos
fonte