Недавно у меня был пример использования в некоторой степени безопасной процедуры обновления для систем на основе U-Boot, где uImage
- это программная ссылка, указывающая на загружаемый образ, идея заключалась в том, что отключение электроэнергии не должно вызывать проблем, независимо от того, на каком этапе процесса это происходит (при условии, что файловая система подыгрывает):
ln image.bin backup_image.bin
ln -sf backup_image.bin uImage
// replace image.bin
ln -sf image.bin uImage
rm backup_image.bin
Без жестких ссылок все было бы не так просто.
/ edit:
Благодаря комментариям я теперь знаю, что было бы лучше сделать:
ln image.bin backup_image.bin
ln -sf backup_image.bin uImageNew
mv uImageNew uImage || rm -rf uImage && mv uImageNew uImage
// replace image.bin
ln -sf image.bin uImageNew
mv uImageNew uImage || rm -rf uImage && mv uImageNew uImage
rm backup_image.bin
( rm
здесь, чтобы иметь возможность лучше избежать странного состояния, например, если uImage
является чем-то неожиданным, что приведет к сбою mv
[но не обязательно предыдущее решение ln -sf
].)
Если вы дадите оболочке текстовую строку для выполнения, она сможет это сделать, если окажется, что она соответствует команде, например "ls"
("ls -l"
не является именем команды).
Ваш первый пример работает, потому что echo
при выполнении команды выполняется вызывающей оболочкой, генерируя bash -c "ls | wc -l"
. Затем конвейер выполняется с помощью bash -c
, что нормально.
Второй, третий и четвертый примеры не работают, поскольку для сгенерированной текстовой строки ls | wc -l
. eval
сделает это за вас.
Причина, по которой "ls -l"
или "ls | wc -l"
не работает, заключается в том, что удаление кавычек происходит после разделения слов в вычислении. командной строки.
Причина, по которой $(echo 'ls | wc -l')
не работает, заключается в том, что подстановка команд также происходит после разделения слов.