Как выполнить несколько команд после xargs -0? - PullRequest
24 голосов
/ 19 сентября 2011
find . -name "filename including space" -print0 | xargs -0 ls -aldF > log.txt
find . -name "filename including space" -print0 | xargs -0 rm -rdf

Можно ли объединить эти две команды в одну, чтобы вместо 2 была сделана только 1 находка?

Я знаю, что для xargs -I могут быть способы сделать это, что может привести к ошибкам при обработке имен файлов, включая пробелы. Любое руководство высоко ценится.

Ответы [ 8 ]

48 голосов
/ 19 сентября 2011
find . -name "filename including space" -print0 | 
  xargs -0 -I '{}' sh -c 'ls -aldF {} >> log.txt; rm -rdf {}'
16 голосов
/ 19 сентября 2011

Если вы просто хотите избежать многократного выполнения find, вы можете сделать tee сразу после find, сохранив вывод find в файл, а затем выполнить строки как:

find . -name "filename including space" -print0 | tee my_teed_file | xargs -0 ls -aldF > log.txt
cat my_teed_file | xargs -0 rm -rdf 

Еще один способ выполнить то же самое (если это действительно то, чего вы хотите достичь) - это сохранить результат find в переменной (предположим, что это не ТБ данных):

founddata=`find . -name "filename including space" -print0`
echo "$founddata" | xargs -0 ls -aldF > log.txt
echo "$founddata" | xargs -0 rm -rdf
5 голосов
/ 20 сентября 2011

Я полагаю, что все эти ответы уже дали правильные способы решения этой проблемы. И я попробовал 2 решения Джонатана и путь Гленна, все из которых отлично работали на моей Mac OS X. Метод mouviciel не работал на моей ОС, возможно, из-за некоторых причин конфигурации. И я думаю, что это похоже на второй метод Джонатана (я могу ошибаться).

Как уже упоминалось в комментариях к методу Гленна, требуется небольшая настройка. Итак, вот команда, которую я попробовал, которая отлично работала. К вашему сведению:

find . -name "filename including space" -print0 | 
xargs -0 -I '{}' sh -c 'ls -aldF {} | tee -a log.txt ; rm -rdf {}'

Или лучше, как предложил Гленн:

find . -name "filename including space" -print0 | 
xargs -0 -I '{}' sh -c 'ls -aldF {} >> log.txt ; rm -rdf {}'
4 голосов
/ 20 сентября 2011

Пока у вас нет новой строки в именах файлов, вам не нужно -print0 для GNU Parallel:

find . -name "My brother's 12\" records" | parallel ls {}\; rm -rdf {} >log.txt

Посмотрите вступительное видео, чтобы узнать больше: http://www.youtube.com/watch?v=OpaiGYxkSuQ

2 голосов
/ 14 октября 2015

Просто вариант подхода xargs без этих ужасных -print0 и xargs -0, вот как я бы это сделал:

ls -1 *.txt  | xargs --delimiter "\n" --max-args 1 --replace={} sh -c 'cat {}; echo "\n"'

Сноска:

  • Да, я знаю, что в именах файлов могут появляться новые строки, но кто в здравом уме это сделает
  • Есть короткие варианты для xargs, но для понимания читателя я использовал длинные.
  • Я бы использовал ls -1, когда я хочу нерекурсивное поведение, а не find -maxdepth 1 -iname "*.txt", что немного более многословно.
1 голос
/ 27 марта 2016

Я опоздал на вечеринку, но есть еще одно решение, которое не было здесь рассмотрено: пользовательские функции. Размещение нескольких инструкций в одной строке является громоздким и может быть трудно читать / поддерживать. Приведенный выше цикл for этого избегает, но есть вероятность превышения длины командной строки.

Вот еще один способ (не проверен).

function processFiles {
  ls -aldF "$@"
  rm -rdf "$@"
}
export -f processFiles

find . -name "filename including space"` -print0 \
  | xargs -0 bash -c processFiles dummyArg > log.txt

Это довольно просто, за исключением "dummyArg", который доставил мне много горя. При запуске bash таким способом аргументы читаются в

"$0" "$1" "$2"  ....

вместо ожидаемого

"$1" "$2" "$3"    ....

Поскольку processFiles {} ожидает, что первый аргумент будет " $ 1 ", мы должны вставить фиктивное значение в " $ 0" .

Footnontes:

  1. Я использую некоторые элементы синтаксиса bash (например, " export -f "), но я считаю, что это адаптируется к другим оболочкам.
  2. Когда я впервые попробовал это, я не добавил фиктивный аргумент. Вместо этого я добавил « $ 0 » в строки аргументов внутри моей функции (например, ls -aldf "$ 0" "$ @" ). Плохая идея. Помимо стилистических проблем, он ломается, когда команда " find " ничего не возвращает. В этом случае для $ 0 установлено значение «bash». Использование вместо этого фиктивного аргумента позволяет избежать всего этого.
1 голос
/ 15 июля 2014

Вы можете выполнить несколько команд после find, используя for вместо xargs:

IFS=$'\n'
for F in `find . -name "filename including space"`
do
    ls -aldF $F > log.txt
    rm -rdf $F
done

IFS определяет внутренний разделитель полей, который по умолчанию равен . Если ваши имена файлов могут содержать пробелы, лучше переопределить их, как указано выше.

0 голосов
/ 19 сентября 2011

Другое решение:

find . -name "filename including space" -print0 \
| xargs -0 -I FOUND echo "$(ls -aldF FOUND > log.txt ; rm -rdf FOUND)"
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...