Linux, почему я не могу найти результат поиска в rm?

извините, если это вопрос новичка, но я не могу найти хороший ответ.

Чтобы найти, а затем удалить что-то, что я могу использовать

find . -name ".txt" -exec rm "{}" \;

Но почему я не могу просто передать результаты в rm, например

find . -name ".txt" | rm 

как будто я бы передал это grep

find . -name ".txt" | grep a

Я где-то читал, что rm не принимает ввод со стандартного ввода, и поэтому я не могу передать его, но что это значит? Когда я набираю rm a.txt, он читается со стандартного ввода так же, как я могу grep, верно? Или есть разница между стандартным вводом и командной строкой. Помощь!


person user1297061    schedule 01.12.2013    source источник


Ответы (5)


Чтобы расширить ответ @Alex Gitelman: да, есть разница между «стандартным вводом» и командной строкой.

Когда вы вводите rm a.txt b.txt c.txt, файлы, которые вы перечисляете после rm, называются аргументами и становятся доступными для rm через специальную переменную (внутренне называемую argv). Стандартный ввод, с другой стороны, выглядит для программы Unix как файл с именем stdin. Программа может читать данные из этого «файла» так же, как если бы она открывала обычный файл на диске и читала из него.

rm, как и многие другие программы, получает аргументы из командной строки, но игнорирует стандартный ввод. Вы можете передать ему все, что захотите; он просто выбросит эти данные. Вот где xargs пригодится. Он считывает строки со стандартного ввода и превращает их в аргументы командной строки, поэтому вы можете эффективно передавать данные в командную строку другой программы. Это ловкий трюк.

Например:

find . -name ".txt" | xargs rm
find . -name ".txt" | grep "foo" | xargs rm  

Обратите внимание, что это будет работать неправильно, если есть какие-либо имена файлов, содержащие символы новой строки или пробелы. Чтобы иметь дело с именами файлов, содержащими символы новой строки или пробелы, вы должны использовать вместо этого:

find . -name ".txt" -print0 | xargs -0 rm

Это скажет find завершать результаты нулевым символом вместо новой строки. Однако тогда grep работать как раньше не будет. Вместо этого используйте это:

find . -name ".txt" | grep "foo" | tr "\n" "\0" | xargs -0 rm

На этот раз tr используется для преобразования всех символов новой строки в нулевые символы.

person Tim Pierce    schedule 01.12.2013
comment
спасибо, это отличный ответ. но как узнать, принимает ли команда аргументы или стандартный ввод, поскольку синтаксически они оба записываются как command something. это включено в справочную страницу? - person user1297061; 01.12.2013
comment
Это не совсем так. По соглашению, многие команды, которые читают из файлов, также будут читать из стандартного ввода, но только если в аргументах командной строки указано никаких файлов. Примеры: cat, less, grep, sort, sed. Но да, в общем случае на справочной странице должно быть указано, считывается ли команда из стандартного ввода, если аргументы не указаны. (Документирование этого остается за авторами справочных страниц Unix. Классические инструменты Unix, как правило, документируются более последовательно, чем более новые. Предостережение.) - person Tim Pierce; 01.12.2013
comment
@user1297061 user1297061 да, это включено в справочную страницу. Если на справочной странице не сказано, что команда принимает ввод со стандартного ввода, значит, она не - person janos; 01.12.2013
comment
Также некоторые команды разрешают стандартный ввод только тогда, когда указано имя файла -. Например, vim: ls | vim - для вывода ls в vim. - person Veda; 09.03.2015
comment
Это отлично сработало для меня. Вместо использования -name .txt я использовал -print, и все остальное работало. Спасибо! - person Harlin; 28.06.2019
comment
В настоящее время вы можете использовать опцию -delete для команды поиска: find . -name "*whatever* -delete. Я не знаю, как проверить, было ли это в 2013 году. - person DerpyNerd; 18.11.2020
comment
@DerpyNerd да, это было верно с находкой GNU (и, вероятно, с большинством других находок) в 2013 году, и это был бы прекрасный способ решить проблему. Но вопрос пользователя в основном касался путаницы стандартного ввода с аргументами командной строки, поэтому этот ответ был сосредоточен на прояснении этой путаницы, а не на попытке найти совершенно другое решение конечной проблемы :-) - person Tim Pierce; 19.11.2020
comment
@TimPierce Ага, хорошо. Должно быть, я пропустил этот поезд :) Справочные страницы великолепны и все такое, но по какой-то причине я предпочитаю гуглить, а не справочные страницы TLDR. Может быть, это все же стоит упомянуть для ленивых людей, таких как я :D - person DerpyNerd; 19.11.2020

"почему я не могу передать результаты поиска в rm?"

Когда вы передаете что-то программе, конвейер заменяет ввод с клавиатуры. Имейте это в виду и задайте себе следующий вопрос: что бы rm делал с клавиатурой? Удалить нажатия клавиш? (немного глупо) Принятие интерактивного управления? (rm не является интерактивным, за исключением случаев, когда требуется подтверждение, которое действительно может быть предоставлено конвейером.)

На самом деле, когда rm уже запущен, вы не можете вводить команды, позволяющие ему удалять файлы... так что вы не можете сделать это и с каналом.

Если иметь в виду, что трубка заменяет комбинацию клавиатуры и экрана, все сразу кажется более логичным.

Теперь наоборот. Вы можете направить поток данных в grep. Означает ли это, что вместо этого вы можете позволить grep считывать нажатия клавиш с клавиатуры в качестве входных данных?

ДА! На самом деле это то, что он делает изначально (без конвейера).

(кстати, обратите внимание, что вы не можете передать или ввести аргумент поиска в grep )

Итак, теперь вы знаете, почему вы не можете передать rm и ожидать, что он будет работать как аргумент командной строки.

tl;dr :

Структура программы в соответствии с философией UNIX:
вход в файл, выход из файла, вход с клавиатуры, выход на экран. -> Pipe заменяет только клавиатуру и экран.

person thom    schedule 01.12.2013
comment
Я почти уверен, что rm <(...) попытается удалить что-то вроде /proc/fd/123. - person jordanm; 01.12.2013
comment
Да, я вижу свою ошибку. На этой неделе я мало спал. Я обновил его. Спасибо за ваш комментарий. Я признателен за это. - person thom; 01.12.2013

Pipe отправляет вывод первой команды на стандартный ввод второй. rm не принимает стандартный ввод, поэтому вы не можете подключиться к нему. Вы можете использовать xargs для достижения того же эффекта. Вы можете найти пример для xargs специально для вашего случая на справочной странице для xargs .

person Alex Gitelman    schedule 01.12.2013

Альтернатива без использования труб:

xargs rm -f <<< $(find . -name ".txt")
person Salvatore De Fidio    schedule 09.02.2016

найти . имя ".txt" | grep "фу" | xargs -I{} пм {}

person user13497656    schedule 08.05.2020