Вопрос или проблема
Я пытаюсь удалить файлы из директории, вставляя их имена в цикл while, который просто выполнит rm для каждого элемента из списка файлов, который ему дан.
$ sponge | while read file; do echo "rm $file"; rm "$file"; done;
background.bundle.js
964.bundle.js
background.bundle.js.LICENSE.txt
...
META-INF/manifest.mf
META-INF/mozilla.sf
META-INF/mozilla.rsa
^D
rm background.bundle.js
rm: удалить обычный файл ‘background.bundle.js’? $
$
(Обратите внимание на ^D в конце)
Как показано, после ввода ^D (конец файла) команда sponge отправляет весь вывод в цикл while, и rm вызывается для каждого файла отдельно. Однако, что происходит, так это то, что он вызывается один раз для background.bundle.js, запрашивает подтверждение и, не дав мне возможности ввести что-либо, цикл выходит преждевременно. Это оставляет символ запроса ($) без необходимого перевода строки, который должен следовать за ним, указывая на резкое завершение цикла.
Я хочу решить эту проблему, не прибегая к временным файлам. Я хочу управлять вводом файлов, используя exec, чтобы цикл читал из другого потока ввода, оставляя стандартный ввод доступным для rm для чтения подтверждения пользователя. Как я могу перенаправить вывод sponge и считать ввод в конкретный файловый дескриптор для этой цели?
Ответ или решение
Вопрос, который вы поднимаете, касается особенностей работы командной строки в Unix-подобных системах, особенно в контексте использования встроенной команды rm
в цикле, который считывает имена файлов из одного потока, в то время как другой поток ожидает ввода для подтверждения удаления. Давайте разберёмся, как можно решить вашу проблему без использования временных файлов, а также как перенаправить вывод и ввод для управления файловыми потоками.
Проблема
Вы столкнулись со следующей ситуацией: после того как команда sponge
завершает выполнение и передает управление в цикл while
, команда rm
вызывает запрос на подтверждение для удаления файла. Однако, когда появляется это сообщение, стандартный ввод уже занят, и вы не можете ввести необходимый ответ, что приводит к преждевременному завершению цикла и неожиданному поведению командной строки.
Решение
Для того чтобы избежать этой проблемы, можно использовать создание новых файловых дескрипторов. Обычный стандартный ввод по умолчанию будет заблокирован, когда rm
ожидает ввода. Тем не менее, вы можете перенаправить вывод команды sponge
через другой файл-дескриптор. Вот как это можно сделать:
-
Создание нового потока: Используйте файловые дескрипторы для управления потоками ввода и вывода.
-
Использование
exec
: Перенаправьте выводsponge
в новый дескриптор, а стандартный ввод оставьте свободным для ввода подтверждений.
Пример кода
Вот пример команды, который использует описанный подход:
exec 3< <(sponge | awk '{ print $0 }') # перенаправление вывода sponge в файл-дескриптор 3
while read -u 3 file; do
echo "rm $file"
rm "$file" # Теперь rm может запрашивать подтверждение, не блокируя стандартный ввод.
done
exec 3<&- # Закрыть файловый дескриптор 3
Объяснение кода
exec 3< <(sponge | awk '{ print $0 }')
: Здесь мы открываем новый файловый дескриптор3
для чтения.sponge
передаёт свой вывод через этот поток, что позволяет обходить блокировку.while read -u 3 file; do
: Мы читаем из нашего нового файла-дескриптора, что позволяетrm
работать с стандартным вводом как обычно.exec 3<&-
: Закрываем дескриптор3
, когда все операции завершены.
Этот метод позволит вам избежать проблемы с блокировкой ввода, предоставляя rm
необходимую возможность для ожидания ввода, не прерывая работу цикла.
Заключение
Ваше понимание работы командной строки и её команд, а также использование файловых дескрипторов, являются хорошим подходом к решению проблем с взаимодействием программ. Используя предложенный метод, вы сможете эффективно обрабатывать удаление файлов, не прибегая к помощи временных файлов и сохраняя интерактивность командной оболочки.
Если у вас возникнут дополнительные вопросы по этой теме или другим аспектам работы с командной строкой, не стесняйтесь задавать их!