Comments 44
Перешёл с xargs на GNU Parallel — сильно быстрее во многих случаях, особенно на сложных операциях над файлами.
> Как видим, файл, в имени которого имеется пробел, не был удалён.
~/Tmp$> touch "new file.sh" new_file.sh
~/Tmp$> find . -name "new*.sh"
./new file.sh
./new_file.sh
~/Tmp$> find . -name "new*.sh" -exec rm -f '{}' \;
~/Tmp$> find . -name "new*.sh"
~/Tmp$>
Эта строка относится к примеру с xargs, и дальше пояснение как этого избежать.
А я понял, что к find:
А вы ниже прочитайте на абзац.
Ну а так, то у find есть ключ -delete.
Ну а так, то у find есть ключ -delete.
И зачем тут тогда вообще нужен xargs? :)
У автора спросите )) Думаю, что просто приведено как пример.
-delete есть в FreeBSD- и GNU-версии find, наверное где-то еще.
Но кроме GNU существует и масса других реализаций find, без -delete. В SunOS например этого нет.
Но кроме GNU существует и масса других реализаций find, без -delete. В SunOS например этого нет.
Я не знаю, где вы это прочитали, но УМВР.
$ touch "test test.sh" "test.sh"
$ ls -l
total 0
-rw------- 1 user group 0 Jan 21 01:16 test.sh
-rw------- 1 user group 0 Jan 21 01:16 test test.sh
$ find . -name "t*.sh" -exec rm -vf '{}' \;
removed ‘./test test.sh’
removed ‘./test.sh’
вашу find конструкцию можно существенно ускорить заменив всего лишь один символ:
find . -name "new*.sh" -exec rm -f '{}' \+
оно отработает существенно быстрее, т.к. не будет на каждый файл отдельно вызывать rm. на паре-тройке файлов это незаметно, но когда счёт идёт на даже на сотни это уже видно невооруженным глазом. и \+ даже не гнутое расширение, а posix. и впилили его уже не один год назад. да (:О, а вот за это — спасибо, не знал о такой штуке (да, я иногда невнимательно читаю длинные мануалы :().
А насколько быстро отработает эта команда на списке из 27 миллионов файлов? Точно ли, если использовать \+, rm не выдаст заветное «too long list of arguments»?
Имхо, с find лучше всего использовать ключ -delete, который просто возьмет и удалит все найденные файлы вне зависимости от их количества.
Имхо, с find лучше всего использовать ключ -delete, который просто возьмет и удалит все найденные файлы вне зависимости от их количества.
«too long list of arguments» вроде же оболочка выдаёт, до rm дело не доходит, а если бы дошло, то, он бы не знал о слишком длинном списке. Вообще xargs умный, если длина команды будет близка к максимальной, то команда вызовется, а накопленный список очистится. "+" не значит, что вызов будет один, он значит, что команда может принимать много аргументов и xargs должен стараться передать как можно больше за раз.
> до rm дело не доходит, а если бы дошло, то, он бы не знал о слишком длинном списке
У меня был случай, когда rm -rf dir/* ругнулось, а rm -rf dir — отработало.
У меня был случай, когда rm -rf dir/* ругнулось, а rm -rf dir — отработало.
в случае с удалением пример немного специфический. вам просто повезло, что у find'a есть -delete. а если вам всё это счастье скопировать нужно? -copy у find'а нет, поэтому либо xargs, либо
find . -options -exec cp -t target {} \+
А для cp нельзя прикрутить, чтобы найденные файлы в указанный каталог перекинуть одним вызовом?
+ обязательно после {} должен идти?
+ обязательно после {} должен идти?
Можно. Если почитать man cp, то можно наткнуться на любопытную опцию -t:
Т.е. выглядит оно примерно так:
Аналогичный трюк можно провернуть с mv.
upd. Что-то я сразу не заметил, ведь именно так и написано в моём предыдущем комментарии. Т.е. оно всё что найдёт и перекинет в указанную директорию. Ну или я вопрос неправильно понял.
-t, --target-directory=DIRECTORY
copy all SOURCE arguments into DIRECTORY
Т.е. выглядит оно примерно так:
find . -type f -exec cp -t TARGET {} \+
Аналогичный трюк можно провернуть с mv.
upd. Что-то я сразу не заметил, ведь именно так и написано в моём предыдущем комментарии. Т.е. оно всё что найдёт и перекинет в указанную директорию. Ну или я вопрос неправильно понял.
Переименование файлов
…
$ ls | sed -e «p;s/.txt$/.sql/» | xargs -n2 fmv
А можно еще проще:
rename 's/\.txt$/.sql' *.txt
Команда rename широко распространена, в debian/ubuntu стоит по умолчанию
У find есть ключик -delete, работает быстрее чем с использованием xargs и exec.
Смотреть:
Тут(GNU.org)
Смотреть:
Тут(GNU.org)
(find /proc/ -name exe -ls 2>/dev/null|awk '{print $13}'|tee /dev/stderr| xargs -n 32 -P 4 ldd 2>/dev/null|grep /|awk '{print $3}') 2>&1|sort -u|xargs -n 1 -P 16 readlink -f|xargs -n 32 -P 4 du -b|awk '{sum+=$1}END{print sum}'
Функциональное программирование в шелле на примере xargs: habrahabr.ru/post/153785/
Функциональное программирование в шелле на примере xargs: habrahabr.ru/post/153785/
Некоторые примеры мягко говоря не совсем подходящие:
* find умеет делать -delete сам
* для упаковки файлов можно использовать обычный пайп: find. -type f | tar czf arc.tgz
* $ cut -d: -f1 < /etc/passwd | sort | xargs echo < — зачем этот echo? sort и так отлично возвращает вывод в stdout
Как-то так.
Сам я чаще всего использую exec внутри find, вместо xargs. В остальных случаях циклы покрывают 99% потребностей. Для работы с именами в которых есть пробелы проще всего экранировать «маркер». Например так:
* find умеет делать -delete сам
* для упаковки файлов можно использовать обычный пайп: find. -type f | tar czf arc.tgz
* $ cut -d: -f1 < /etc/passwd | sort | xargs echo < — зачем этот echo? sort и так отлично возвращает вывод в stdout
Как-то так.
Сам я чаще всего использую exec внутри find, вместо xargs. В остальных случаях циклы покрывают 99% потребностей. Для работы с именами в которых есть пробелы проще всего экранировать «маркер». Например так:
bash-4.2# ls
a b c d
bash-4.2# touch "1 2 3 4"
bash-4.2# ls | xargs -I{} mv "{}" "{}".sh
bash-4.2# ls
1 2 3 4.sh a b c d.sh
bash-4.2#
Всегда думал — «Как Тираны обходились такими маленькими ручками?»
Теперь я все понял! Спасибо :)
ЗЫ *nix советы тоже интересны и поучительны, но картинка… Это нечто.
Теперь я все понял! Спасибо :)
ЗЫ *nix советы тоже интересны и поучительны, но картинка… Это нечто.
А давайте усугубим пример с find… | xargs rm. Для этого сначала почти бесправный пользователь bob делает:
Потом всевластный root в скрипте по крону пишет:
И в итоге некоторые файлы не то, чтобы совсем не удаляются, но удаляются не те, что нужно.
Место для хождения по граблям в статье выделено совершенно правильно, да и аргументом xargs может быть не только rm.
mkdir "~bob/user-controlled/space /etc"
touch "~bob/user-controlled/space /etc/passwd"
Потом всевластный root в скрипте по крону пишет:
find ~bob -name "*" | xargs rm -f
И в итоге некоторые файлы не то, чтобы совсем не удаляются, но удаляются не те, что нужно.
Место для хождения по граблям в статье выделено совершенно правильно, да и аргументом xargs может быть не только rm.
# самое простое
find -name ... -delete
# удалять файлы в 4 потока по 8 штук за раз
find -type f -name ... -print0 | xargs -0 -P$(nproc) -n8 rm
Насчёт параллельного запуска да и самого xargs можно было и побольше примеров придумать:
# нехитрый способ конвертировать все mp3 в ogg
find -name '*.mp3' -print0 | xargs -0 -n1 -P$(nproc) sh -c 'ffmpeg -v quiet -y -i "$0" -vn -codec vorbis -aq 2 "${0%mp3}ogg"'
# поиск несмердженных веток Git
git branch -r --no-merged | grep -v HEAD | xargs -L1 git --no-pager log --pretty=tformat:'%Cgreen%d%Creset - %h by %an (%Cblue%ar%Creset)' -1
# wget в 8 потоков (список ссылок для загрузки лежит в файле .list)
< .list xargs -I{} -P8 sh -c 'echo {}; wget -q {}'
# универсальный скрипт - функция _worker выполнится для каждого подкаталога в текущем каталоге (в несколько потоков, разумеется)
_worker() {
cd "$1"
# ...что-то делаем
}
export -f _worker
find . -maxdepth 1 -mindepth 1 -type d | xargs -P$(nproc) -I{} bash -c '_worker {}'
find, xargs и nproc выручают меня постоянно, особенно когда речь идёт о серверах с кучей ядер. В статье как-то скудновато описано.
мне как-то нужно было скачать первую страницу всех сайтов рунета.
сначала через fping определи все домены которые резолвятся и сохранил их в отдельный файл, а потом
где crawler.sh это просто wget c нужными настройками (таймаутами). За 6 часов все скачалось.
сначала через fping определи все домены которые резолвятся и сохранил их в отдельный файл, а потом
cat unqiq.domains.txt | xargs -P 800 -I _URL_ ./crawler.sh _URL_
где crawler.sh это просто wget c нужными настройками (таймаутами). За 6 часов все скачалось.
Я может чего не понял, xargs иногда путает, но вот это:
«С помощью xargs можно также добавлять к дополнительные элементы к именам файлов (например, дату):
$ ls | xargs -I FILE mv {} <… >-{}»
— не будет работать. Тогда уж так:
$ ls | xargs -I FILE mv FILE <… >-FILE
Ну и в других местах…
«С помощью xargs можно также добавлять к дополнительные элементы к именам файлов (например, дату):
$ ls | xargs -I FILE mv {} <… >-{}»
— не будет работать. Тогда уж так:
$ ls | xargs -I FILE mv FILE <… >-FILE
Ну и в других местах…
какую задачу выполняет xargs в комманде?
PS: Ждем след статью на тему «как использовать grep и echo»
tr -dc A-Za-z0-9_ < /dev/urandom | head -c 10 | xargs
PS: Ждем след статью на тему «как использовать grep и echo»
tr -dc A-Za-z0-9_ < /dev/urandom | head -c 10 | grep ''
tr -dc A-Za-z0-9_ < /dev/urandom | head -c 10 && echo
По iptables — не стоит применять длинные линейные списки там, где можно применить ipset.
UFO just landed and posted this here
Sign up to leave a comment.
Xargs: многообразие вариантов использования