Благодаря ответ, который я получил на один из моих вопросов , я нашел другое решение . Итак, для полноты картины, вот решение, использующее find
:
find . -path './.git' -prune -o -print |
tar -czvf ../archive.tgz --no-recursion -T -
И если вы хотите исключить возможные папки .git
внутри (sub) + folder :
find . -path '*/.git' -prune -o -print |
tar -czvf ../archive.tgz --no-recursion -T -
Последнее также может быть достигнуто с помощью:
find . -type d -name '.git' -prune -o -print |
tar -czvf ../archive.tgz --no-recursion -T -
Очень удобно, если вы можете использовать другие методы фильтрации из find
, например дата модификации, разрешения,…
(Поскольку часто подразумеваются правильно сформированные имена файлов, в противном случае вам нужно использовать нулевые байты в качестве разделителей, что может означать -print0
для find
и - null
для tar
, если поддерживается.)
Да, PIPE создает статус выхода; если вам нужен код выхода команды перед PIPE, вы можете использовать $PIPESTATUS
В соответствии с этими вопросами и ответами по переполнению стека, чтобы распечатать статус выхода команды при использовании канала вы можете сделать:
your_command | echo $PIPESTATUS
Или установить pipefail с помощью команды set -o pipefail
(чтобы отменить его, выполните set +o pipefail
) и используйте $?
вместо $PIPESTATUS
.
your_command | echo $?
Эти команды работают только после того, как вы запустите их хотя бы один раз; это означает, что PIPESTATUS
работает только тогда, когда вы запускаете его после команды с конвейером, например:
command_which_exit_10 | command_which_exit_1
echo "${PIPESTATUS[0]} ${PIPESTATUS[1]}"
Вы получите 10 за ${PIPESTATUS[0]}
и 1 за ${PIPESTATUS[1]}
.
Дополнительную информацию см. в этом вопросе и ответе U&L.
Статус выхода канала — это статус выхода правой команды. Статус выхода левой команды игнорируется.
(Обратите внимание, что what lss | echo $?
этого не показывает. Вы должны запустить what lss | true; echo $?
, чтобы показать это. В which lss | echo $?
, echo $?
сообщает о состоянии последней команды перед этим конвейером.)
Причина, по которой оболочки ведут себя таким образом, заключается в том, что существует довольно распространенный сценарий, при котором возникает ошибка. в левой части следует игнорировать. Если правая сторона выходит (или, в более общем случае, закрывает свой стандартный ввод), в то время как левая сторона все еще записывает, то левая сторона получает сигнал SIGPIPE. В этом случае обычно нет ничего плохого: правая часть не заботится о данных; если роль левой стороны состоит исключительно в том, чтобы производить эти данные, то она может остановиться.
Однако, если левая сторона умирает по какой-либо причине, отличной от SIGPIPE, или если задача левой стороны заключалась не только в создании данных на стандартном выходе, то ошибка в левой части является ошибкой. подлинная ошибка, о которой следует сообщить.
В простом sh единственным решением является использование именованного канала.
set -e
mkfifo p
command1 >p & pid1=$!
command2 <p
wait $pid1
В ksh, bash и zsh вы можете указать оболочке сделать выход конвейера с ненулевым статусом, если какой-либо компонент конвейера завершается с ненулевым статусом.Вам необходимо установить параметр pipefail
:
set -o pipefail
shopt -s pipefail
setopt pipefail
] (или setopt pipe_fail
) В mksh, bash и zsh вы можете получить статус каждого компонента конвейера, используя переменную PIPESTATUS
(bash, mksh) или pipestatus
(zsh), который представляет собой массив, содержащий статус всех команд в последнем конвейере (обобщение $?
).
Статус выхода конвейера — это статус выхода последней команды в конвейере (если не указан параметр оболочки pipefail
устанавливается в оболочках, которые его поддерживают, и в этом случае статус выхода будет таким же, как у последней команды в конвейере, которая завершается с ненулевым статусом).
Невозможно вывести статус выхода конвейера из конвейера, поскольку невозможно узнать, каким будет это значение, пока конвейер фактически не завершит выполнение.
Конвейер
which lss | echo $?
не имеет смысла, поскольку echo
не считывает свой стандартный ввод (конвейеры используются для передачи данных между выводом одной команды и вводом следующей). echo
также не будет печатать статус выхода конвейера, но статус выхода команды запускается сразу перед конвейером.
$ false
$ which hello | echo $?
1
which: hello: Command not found.
$ true
$ which hello | echo $?
0
which: hello: Command not found.
Это лучший пример:
$ echo hello | read a
$ echo $?
0
$ echo nonexistent | { read filename && rm $filename; }
rm: nonexistent: No such file or directory
$ echo $?
1
Это означает, что конвейер также может использоваться с if
:
if gzip -dc file.gz | grep -q 'something'; then
echo 'something was found'
fi
Оболочка оценивает командную строку перед выполнением конвейера. Итак, $?
— это значение последней команды, выполненной перед конвейером. Запускается ли сам echo
до или после , который
не имеет значения.
Теперь, если ваш вопрос был конкретно о распространении статуса выхода, вы можете изучить поведение по умолчанию следующим образом:
% false | true
% echo $?
0
% true | false
% echo $?
1
Как видите, статус выхода конвейера — это статус выхода его последней команды.