Моя проблема (в сценарии с #!/bin/sh
) заключается в следующем: я пытаюсь контрольную сумму всех файлов в каталоге для архивных целей. Файл контрольной суммы (в моем случае sha1) со всеми именами файлов должен находиться в одном каталоге. Допустим, у нас есть каталог ~/test
с файлами f1
и f2
:.
mkdir ~/test
cd ~/test
echo "hello" > f1
echo "world" > f2
Теперь вычисление контрольных сумм с
find -maxdepth 1 -type f -printf '%P\n' | xargs shasum
делает именно то, что я хочу, он перечисляет все файлы только текущего каталога и вычисляет суммы sha1 (maxdepth может быть изменен позже). Выход на STDOUT:
f572d396fae9206628714fb2ce00f72e94f2258f f1
9591818c07e900db7e1e0bc4b884c945e6a61b24 f2
К сожалению, при попытке сохранить это в файл с
find -maxdepth 1 -type f -printf '%P\n' | xargs shasum > sums.sha1
результирующий файл отображает контрольную сумму для себя:
da39a3ee5e6b4b0d3255bfef95601890afd80709 sums.sha1
f572d396fae9206628714fb2ce00f72e94f2258f f1
9591818c07e900db7e1e0bc4b884c945e6a61b24 f2
и, следовательно, не удается позже shasum --check
, из-за очевидной проблемы дополнительной модификации файла при сохранении последней суммы.
Я огляделся и, используя -p
флаг for xargs
, обнаружил, что он каким-то образом создает выходной файл еще до выполнения команды find, поэтому дополнительный файл найден и будет проверен ...
Я знаю, что в качестве обходного пути я мог бы сохранить контрольную сумму в другом месте (через временный каталог mktemp
) или исключить ее из функции find, но я хотел бы понять, почему она ведет себя так, как она работает - что, на мой взгляд, не очень полезно, например, если первая команда проверит, находится ли выходной файл на диске, она никогда не получит правильный ответ ...
xargs
, именно сама оболочка создает этот файл, потому что перед выполнением любой команды оболочка перенаправляет все входные, выходные и конвейерные данные, так что приfind
запуске выходной файл уже существует. Используйте-exec
вместо:find -maxdepth 1 -type f -exec sh -c 'shasum "$@" > sums.sha1' {} +
sh
вызовов. Обратите внимание, что вам нужен аргумент для$0
ранее{}
.tee
исчез? Я попробовал, и он работает нормально, я также подавил STDOUT с добавлением1>/dev/null
. Было ли что-то не так с ответом или это ошибка?Ответы:
Вы можете предотвратить доступ к файлу,
xargs
используя:Чтобы избежать проблем с именами файлов, которые содержат пробелы, символы новой строки, кавычки или обратную косую черту, я бы использовал:
вместо.
--
, Чтобы избежать проблем с именами файлов , которые начинаются с-
. Однако это не поможет для файла с именем-
. Если бы вы использовали-print0
вместо-printf '%P\0'
, вам бы не нужно--
и не было бы проблемы с-
файлом.источник
basename
для получения имени файла sums.sha1 из указанного полного пути (это не было включено в вопрос, но это могло бы помочь другим).Поскольку вы используете
-maxdepth 1
, я предполагаю, что вы не хотите рекурсии. Если это так, просто сделайте это в оболочке:Чтобы пропустить каталоги, вы можете сделать:
Если вам нужна рекурсия и вы используете
bash
, выполните:Обратите внимание, что все эти подходы имеют преимущество работы с произвольными именами файлов, в том числе с пробелами, переводами строки или чем-то еще.
источник
sums.sha1
оно уже есть (из предыдущего прогона), ваше решение включит его.sh
, но ваш ответ может помочь другим.с
zsh
:Глобус будет расширен до перенаправления, поэтому
sums.sha1
он не будет включен, если его не было в первую очередь.D
это включить точечные файлы (скрытые файлы), как еслиfind
бы.
это выбрать только обычные файлы (например, ваши-type f
).Чтобы исключить в
sums.sha1
любом случае, если он был там в первую очередь:Обратите внимание, что они запускают одну команду shasum, поэтому вы можете в конечном итоге увидеть ошибку «Arg list too long», если список огромен. Чтобы обойти это:
Я бы рекомендовал использовать
./*
вместо,*
чтобы избежать потенциальных проблем с файлом с именем-
.источник
Как уже говорилось в других ответах, проблема в том, что оболочка открывается и создает
sums.sha1
файл перед выполнением вашего конвейера. Вы можете использовать программу,sponge
которая входит вmoreutils
пакет многих дистрибутивов. В отличие от оболочки перенаправлениеsponge
будет ждать, пока не получит все, прежде чем открывать файл. Обычно используется, когда вы хотите записать файл, который вы читаете в том же конвейере.В вашем случае это используется так:
источник
В качестве альтернативы find / xargs и т. Д. Вы можете использовать sha1deep. Хотя, вероятно, он находится в другом пакете - на моей коробке он входит в пакет md5deep.
Как уже говорили другие, sums.sha1 создается оболочкой еще до начала поиска. Хитрость в том,
! -name sums.sha1
чтобыfind
будет работать, как будетисточник