В дополнение к другому прекрасному ответу относительно консалтинга с документацией я всегда обращаюсь к средству отладки 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.
с 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
while read i; do echo cp \""$i"\" \"$(grep "/$i$" dst.txt)\"; done < src.txt
Будет напечатано то, что должно было быть сделано. Просто избавьтесь от echo
, чтобы скопировать файлы.
Однострочный скрипт порождает скрипт, который порождает скрипт.
В этом примере мы используем первый вызов 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
Я не уверен, что это точно - или даже близко - то, что вы хотите, но вы можете использовать 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
...и поэтому вам нужно беспокоиться только о парах строк, начинающихся с той, которая не соответствует /
.