
Этот скрипт иногда дает сбой, а иногда работает успешно (очень раздражающая ситуация):
#!/bin/bash
set -Eeuxo pipefail
test_dir="$(mktemp -d)"
touch "$test_dir/file"{001..312}
latest_file="$(find $test_dir -type f | sort -r | head -n1)"
echo $latest_file
В случае успеха он регистрирует что-то вроде этого:
++ mktemp -d
+ test_dir=/tmp/tmp.yWelcpBYB7
+ touch /tmp/tmp.yWelcpBYB7/file001 /tmp/tmp.yWelcpBYB7/file002 ... /tmp/tmp.yWelcpBYB7/file312
++ find /tmp/tmp.yWelcpBYB7 -type f
++ head -n1
++ sort -r
+ latest_file=/tmp/tmp.yWelcpBYB7/file312
+ echo /tmp/tmp.yWelcpBYB7/file312
/tmp/tmp.yWelcpBYB7/file312
В случае сбоя регистрируется что-то вроде этого:
++ mktemp -d
+ test_dir=/tmp/tmp.VzTqmgpZyG
+ touch /tmp/tmp.VzTqmgpZyG/file001 /tmp/tmp.VzTqmgpZyG/file002 ... /tmp/tmp.VzTqmgpZyG/file312
++ find /tmp/tmp.VzTqmgpZyG -type f
++ sort -r
++ head -n1
+ latest_file=/tmp/tmp.VzTqmgpZyG/file312
Обратите внимание, что echo $latest_file
линиянетвыполняется здесь, хотя он отображается в xtrace
Я не могу добиться успешного запуска, если использую 10 000 файлов, поэтому я подозреваю, что это как-то связано сголоваостановканаходитьрано.
#!/bin/bash
set -Eeuxo pipefail
test_dir="$(mktemp -d)"
touch "$test_dir/file"{0000..9999}
latest_file="$(find $test_dir -type f | sort -r | head -n1)"
echo $latest_file
Если я подавляю остановку при ошибке (используянабор +е), это удается:
#!/bin/bash
set -Eeuxo pipefail
test_dir="$(mktemp -d)"
touch "$test_dir/file"{0000..9999}
set +e
latest_file="$(find $test_dir -type f | sort -r | head -n1)"
set -e
echo $latest_file
Почему этот скрипт не регистрирует последний файл?
решение1
Проблема в том, что -e
. Почему? -e
заставляет bash прерывать работу в случае, если процесс завершается с ненулевым кодом выхода (полные правила немного сложнее). Если есть канал, учитывается только последняя команда.
Вы head -n1
создаете внутреннюю ситуацию ошибки, поскольку вам приходится как бы разрывать канал (вы можете проверить это с помощью strace
), чтобы игнорировать оставшуюся часть вывода от sort
.
Итак, чтобы ваш скрипт работал надежно с -e
, вы можете добавить cat
в конец конвейера. head
все равно разорвет конвейер, но поскольку это уже не последняя команда в нем, она не будет учитываться -e
. cat
является пустой операцией для конвейера:
#!/bin/bash
set -Eeuxo pipefail
test_dir="$(mktemp -d)"
touch "$test_dir/file"{0000..9999}
latest_file="$(find $test_dir -type f | sort -r | head -n1 | cat)"
echo $latest_file
пожалуйста, проверьтеПочему set -e (или set -o errexit, или trap ERR) не делает то, что я ожидал?узнать, почему -e
такая нестабильная функция и какие проблемы она может вызвать. В конце есть много примеров. Мой любимый:
#!/bin/bash
set -e
foo=$(expr 1 - 1)
echo survived
Это будетнетРаспечататьвыжил, эта строка не будет выполнена. Но, если бы у вас было foo=$(expr 2 - 1)
, то echo
было бы выполнено!
Лучше бы вам реализовать собственную проверку ошибок, -e
это не лучшее решение.