Перемещение списка файлов путем сопоставления их с индексом назначения

В дополнение к другому прекрасному ответу относительно консалтинга с документацией я всегда обращаюсь к средству отладки Bash для наблюдения то, что продолжается.

Можно включить его и отключить его путем обертывания команд интереса к блоку как так:

$ set -x; command_to_watch; set +x

Пример

$ set -x; export JDK_HOME=${JDK_HOME:-"/some/path/java-1.7"}; set +x
+ export JDK_HOME=/some/path/java-1.7
+ JDK_HOME=/some/path/java-1.7
+ set +x

Здесь Вы видите что переменная $JDK_HOME устанавливается на /some/path/java-1.7. Однако, если мы устанавливаем его на что-то еще:

$ export JDK_HOME=/a/path
$ echo $JDK_HOME
/a/path

И выполненный эта команда снова:

$ set -x; export JDK_HOME=${JDK_HOME:-"/some/path/java-1.7"}; set +x
+ export JDK_HOME=/a/path
+ JDK_HOME=/a/path
+ set +x

Мы видим, что это ничего не сделало, ведя нас к тому, что, если переменная уже установлена, эта команда оставит ее в покое, иначе это установит его со значением, /some/path/java-1.7.

Подтверждение нашего подозрения в странице справочника Bash:

${parameter:-word}
      Use Default Values.  If parameter is unset or null, the expansion of word
      is substituted.  Otherwise, the value of parameter is substituted.

3
06.11.2015, 00:29
4 ответа

с zsh :

src=(${(f)"$(<src.txt)"})
for f (${(f)"$(<dest.txt)"})
(($src[(Ie)$f:t])) && mv /src/dir/$f:t $f

Читает каждый файл в массиве, а затем для каждого элемента в массиве "dest" , если базовое имя (: t - это модификатор zsh , который удаляет все ведущие компоненты имени пути) также находится в массиве «src» , затем он перемещает файл. Для выполнения пробного запуска replace mv с printf '"% s" -> "% s" \ n' .


Теперь вы также можете запустить (все еще в zsh ):

for f (${(f)"$(grep -Ff src.txt dest.txt)"})
mv /src/dir/$f:t $f

, который работает нормально, пока ни одно из имен файлов в src.txt не соответствует ни одному каталогу имена (или часть этого имени) в списке путей в dest.txt (например, имя файла data1 в src.txt и путь вроде / path / data1_dir / some_file в dest.txt даст ложное срабатывание). Чтобы избежать этого, вы можете передать имена файлов в grep в виде шаблонов (т. Е. Используя регулярное выражение типа / filename $ ) вместо F фиксированных строк, чтобы они соответствовали только последний компонент путей в dest.txt . Хотя это требует экранирования всех специальных символов (если они есть) в именах файлов в src.txt , например на этот раз с bash ( 4 ):

readarray -t files < <(sed 's|[[\.*^$/]|\\&|g;s|.*|/&$|' src.txt | grep -f- dest.txt)
for f in "${files[@]}"; do mv /src/dir/"${f##*/}" "$f"; done
3
27.01.2020, 21:14
while read i; do echo cp \""$i"\" \"$(grep "/$i$" dst.txt)\"; done < src.txt

Будет напечатано то, что должно было быть сделано. Просто избавьтесь от echo , чтобы скопировать файлы.

1
27.01.2020, 21:14

Однострочный скрипт порождает скрипт, который порождает скрипт.

В этом примере мы используем первый вызов sed на src.txt для создания второго sed скрипта, который будет запущен на dest.txt для создания сценария оболочки для копирования файлов.

Вот односложно:

$ sed -n "$(sed 's,\(..*\),/\\/\1$/ { s/^/cp "\1" "/; s/$/";/; p; },' src.txt)" dest.txt #| sh -x

и вывод:

cp "file 3.jpg" "/dest/dir 1/file 3.jpg";
cp "file 1.jpg" "/dest/dir 2/file 1.jpg";
cp "file_2.html" "/dest/file_2.html";

Обратите внимание на комментарий #| sh в конце команды. Таким образом, вы можете попробовать команду и посмотреть, что она будет делать, и если все будет хорошо, разкомментировать трубу до sh и действительно скопировать файлы.

Команда inner sed создает sed-скрипт из src.txt. Первая строка сгенерированного скрипта выглядит так:

/\/file 1.jpg$/ { s/^/cp file 1.jpg /; p; }

Вот как это работает:

Вход:

    $ cat src.txt
    file 1.jpg
    file_2.html
    file 3.jpg

    $ cat dest.txt
    /dest/dir 1/file 3.jpg
    /dest/file4.txt
    /dest/file 5.txt
    /dest/dir 2/file 1.jpg
    /dest/file_2.html

Первый вызов sed. Здесь показан сгенерированный сценарий, который будет интерпретирован вторым вызовом sed:

$ sed 's,\(..*\),/\\/\1$/ { s/^/cp "\1" "/; s/$/";/; p; },' src.txt
/\/file 1.jpg$/ { s/^/cp "file 1.jpg" "/; s/$/";/; p; }
/\/file_2.html$/ { s/^/cp "file_2.html" "/; s/$/";/; p; }
/\/file 3.jpg$/ { s/^/cp "file 3.jpg" "/; s/$/";/; p; }

Используйте подстановку команд оболочки, чтобы использовать вывод первой команды sed как сценарий в командной строке, переданный второму вызову sed:

$ sed -n "$(sed 's,\(..*\),/\\/\1$/ { s/^/cp "\1" "/; s/$/";/; p; },' src.txt)" dest.txt
cp "file 3.jpg" "/dest/dir 1/file 3.jpg";
cp "file 1.jpg" "/dest/dir 2/file 1.jpg";
cp "file_2.html" "/dest/file_2.html";

Теперь передайте вывод sed в оболочку с опцией xtrace (sh -x). У меня нет ни одного из этих файлов, отсюда ошибки:

$ sed -n "$(sed 's,\(..*\),/\\/\1$/ { s/^/cp "\1" "/; s/$/";/; p; },' src.txt)" dest.txt  | sh -x
+ cp file 3.jpg /dest/dir 1/file 3.jpg
cp: cannot stat ‘file 3.jpg’: No such file or directory
+ cp file 1.jpg /dest/dir 2/file 1.jpg
cp: cannot stat ‘file 1.jpg’: No such file or directory
+ cp file_2.html /dest/file_2.html
cp: cannot stat ‘file_2.html’: No such file or directory
0
27.01.2020, 21:14

Я не уверен, что это точно - или даже близко - то, что вы хотите, но вы можете использовать DRBD на экспортированной iscsi ZFS zvol. На самом деле, вам даже не нужно DRBD для этого, вы можете просто экспортировать два zvol с двух разных серверов ZFS с помощью iscsi и сделать linux mdadm raid устройство с ними в целевой системе.

Существует дополнительный модуль для системы управления виртуальными машинами компании Google ganeti для выполнения этой задачи с помощью DRBD и ZFS zvols по адресу https://github.com/ffzg/ganeti-extstorage-zfs , что может служить полезным примером того, как это сделать. Ganeti уже делает что-то подобное с LVM и DRBD, поэтому это просто расширяет возможности для включения ZFS.

btrfs не имеет zvols или что-либо эквивалентное, поэтому AFAIK не может делать с btrfs.

-121--116192-

Используйте find :

Когда вы говорите не рекурсивно, вы имеете в виду, что вы хотите только количество файлов/каталогов в/home, но не подкаталоги? В этом случае можно ограничить результаты до верхнего уровня с помощью опции maxdepth .

find /home -maxdepth 1 | wc -l

Использование для:

i=0; for home in ~/*; do (( i++ )); done; echo $i

Запишите места между двойными скобками и заключенными i++.

-121--105130-

Если новая строка является приемлемым разделителем, то в оболочке POSIX должны быть достаточно надежными:

IFS='
';set -f
for   f in $(cat <"$destfile")
do    [ -e "./${f##*/}" ] ||
      [ -h "./${f##*/}" ] &&
      mv   "./${f##*/}"  "$f"
done

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

  • Размер входного файла просто слишком велик, чтобы его можно было разделить таким образом.

    • В моей системе это даже не имеет серьезного значения до тех пор, пока входные данные не приблизятся к десяткам тысяч строк.
  • Имя файла в $ destfile может существовать в текущем каталоге и в любом случае не должно перемещаться.

    • Поскольку это решение не позволяет полностью сравнить два входных файла и проверяет наличие в текущем каталоге только каждого компонента пути к фамилии в $ destfile , если какие-либо имена файлов могут совпадать непреднамеренно, его не следует рассматривать.

Если требуется только первая проблема:

sed -ne"s|'|'"'\\&&|g' <"$destfile"    \
    -e "s|.*/\([^/].*\)|_mv './\1' '&'|p" | 
sh  -c '_mv(){ [ -e "$1" ]||[ -h "$1" ]&& mv "$@";};. /dev/fd/0'

Если sh это тире , вы можете удалить ./dev/fd/0 в конце и использовать:

sed ... | sh -cs '_mv(){ ...;}'

..., потому что тире странно обрабатывает как командную строку, так и параметры вызова stdin согласованно и без претензий. Это было бы не очень портативно, но ./dev/fd/0 - хотя и довольно портативно - также не соответствует строгим стандартам.

Если вторая проблема вызывает обеспокоенность:

export  LC_ALL=C 
sed  -ne'\|/$|!s|.*/\(.*\)|\1/&|p' <"$destfile" |
sort -t/ -k1,1 - ./"$srcfile"  |  cut  -d/ -f2- |
sed  -e "\|/|!N;\|\n.*/|!d"    \
     -e "s|'|'"'\\&&|g'        \
     -e "s|\n|' '|;s|.*|mv './&'|" | sh

... это должно быть очень красиво до тех пор, пока все имена файлов в ./« $ srcfile » правильно и одинаково учитываются в конце некоторого пути в « $ destfile ». sort всегда будет плавать короче двух в остальном идентичных сравнений к верху, и поэтому, когда имеет значение только первое поле, и имя файла добавляется к заголовку каждого пути из «$ destfile» , тогда объединенная операция сортировки обоих файлов будет выводить последовательности, такие как:

$srcfile:  no /
$destfile: match
$destfile: unique
$destfile: unique
...
$srcfile:  no /
$destfile: match
$destfile: unique

...и поэтому вам нужно беспокоиться только о парах строк, начинающихся с той, которая не соответствует /.

2
27.01.2020, 21:14

Теги

Похожие вопросы