Правильно экранирование косой черты в bash-скрипте для использования с sed


14

Я пытаюсь определить размер файлов, которые будут скопированы при синхронизации двух папок, запустив rsync в сухом режиме, а затем суммируя размеры файлов, перечисленных в выходных данных rsync.

В настоящее время я застрял в префиксе файлов по их родительской папке. Я узнал, как префиксировать строки, используя sed, и как избежать использования sed, но у меня проблемы с объединением этих двух.

Вот как далеко я получил:

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

Это вывод, который я получаю из 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

Любые идеи о том, как правильно избежать, будут высоко оценены.

Ответы:


28

Вам на самом деле не нужно беспокоиться о побеге /. Из GNU sedруководства :

Эти /символы могут быть равномерно заменены любым другим символом в том или иной sкоманде.

Например:

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

дает вывод

barbar

4
Это должно быть первым на странице руководства для sed
Clearer

Любой как в 'любом' *?
Уджвал Сингх

0

Если вы пытаетесь объединить данные, вы, вероятно, захотите пропустить любые возможные подкаталоги. Это может быть неприменимо, но всегда лучше избегать каких-либо странностей. Вот мой исходный каталог. Все эти файлы были созданы с помощью touch, поэтому они занимают 0 места.

$ 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

Вам не нужно бежать так близко, как вы делаете. Блок sed здесь будет делать следующее:
1d; удалить первую строку «отправки списка добавочных файлов»
/ ^ $ /, $ d; удалите пустую строку, которая обозначает конец списка файлов и все, что после него.
// $ / d удаляем любую строку, оканчивающуюся на '/', которая будет каталогом.
Обратите внимание, что вы можете избежать косой черты с обратной косой чертой (чтобы ответить на реальный вопрос).

$ 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

А для дополнительных бонусных баллов вы можете даже подсчитать результаты:

$ 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

Если вы делаете это с уже полностью синхронизированным каталогом, он выдаст забавные результаты, хотя:

76  .
sum: 76
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.