Prawidłowe unikanie ukośnika w skrypcie bash do użycia z sed

14

Próbuję określić rozmiar plików, które zostaną nowo skopiowane podczas synchronizacji dwóch folderów, uruchamiając rsync w trybie suchym, a następnie sumując rozmiary plików wymienionych na wyjściu rsync.

Obecnie utknąłem przy prefiksowaniu plików według ich folderu nadrzędnego. Dowiedziałem się, jak prefiksować linie za pomocą sed i jak uciec za pomocą sed, ale mam problemy z połączeniem tych dwóch.

Oto jak daleko doszedłem:

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}'

To jest wynik, który otrzymuję z 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

Wszelkie pomysły, jak właściwie uciec, będą bardzo mile widziane.

użytkownik331839
źródło

Odpowiedzi:

28

Tak naprawdę nie musisz zawracać sobie głowy ucieczką /. Z podręcznika GNUsed :

Te /znaki mogą być równomiernie zastąpiony przez inny pojedynczy znak w danym spoleceniu.

Na przykład:

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

daje wynik

barbar
jjlin
źródło
4
To powinna być pierwsza rzecz na stronie podręcznika dla sed
Clearer
Jakikolwiek jak w „any” *?
Ujjwal Singh,
0

Jeśli próbujesz zsumować dane, prawdopodobnie zechcesz pominąć wszystkie możliwe podkatalogi. Może to nie mieć zastosowania, ale zawsze najlepiej jest unikać dziwności. Oto mój katalog źródłowy. Wszystkie te pliki zostały utworzone za pomocą dotyku, więc zajmują 0 miejsca.

$ 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

Nie powinieneś uciekać nigdzie tak blisko, jak to robisz. Blok sed w tym miejscu wykona następujące czynności:
1d; usuń pierwszy wiersz „wysyłania przyrostowej listy plików”
/ ^ $ /, $ d; usuń pusty wiersz oznaczający koniec listy plików i wszystko po nim.
// $ / d usuń dowolny wiersz kończący się na „/”, który byłby katalogiem
Zauważ, że możesz uciec przed ukośnikami za pomocą ukośników odwrotnych (aby odpowiedzieć na aktualne pytanie).

$ 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

Aby uzyskać dodatkowe punkty bonusowe, możesz nawet zsumować wyniki:

$ 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

Jeśli robisz to z katalogiem już w pełni zsynchronizowanym, zwróci to śmieszne wyniki:

76  .
sum: 76
Falsenames
źródło