Игнорировать пустые результаты для xargs в Mac OS X
Код для моего сайта использует этот фрагмент кода для автоматического развертывания на сервере (Ubuntu).
cmd = 'cd ' + checkout_dir + ' && ' + svn_command + " st | awk '{print $2}' | grep -v ^deploy | tac | xargs -r" + svn_command + " revert -R && " + svn_command + ' up -r ' + options.revision
То, что делает эта команда, это cd
в каталоге checkout, запускает svn status
, а затем извлекает имя файла ($2
), удаляет каталог deploy
и все его файлы из списка (я не хочу вернуть его). Если аргументов нет, он не запускает команду svn revert, иначе это произойдет.
К сожалению, xargs -r
не работает на моей машине (Mac OS X 10.8). Поэтому я застрял здесь, может ли кто-нибудь помочь?
Ответы
Ответ 1
Действительно, реализация BSD xargs
не имеет флага -r
(--no-run-if-empty
). Версия GNU в Linux имеет его.
Здесь один из способов обойти проблему таким образом, который работает как в Linux, так и в BSD:
... | (grep -v ^deploy || echo :) | xargs svn revert
grep ... || echo :
в середине будет генерировать строку с :
в ней, если вывод grep
пуст. Это немного грязно, потому что xargs
все равно выполнит команду svn revert :
. Если ваш репозиторий не содержит файл :
, тогда это не должно иметь никакого эффекта, поэтому оно может быть приемлемым. :
может быть чем угодно, если в вашем репозитории нет такого файла.
Наконец, как отметил @tripleee, grep ... || echo :
должен быть заключен в (...)
, потому что:
||
имеет более высокий приоритет, чем |
, и таким образом завершает (первый) конвейер.
Ваш код выглядит как строка Python. Это будет более читаемым следующим образом:
kwargs = {
'svn': svn_command,
'dir': checkout_dir,
'revno': options.revision,
}
cmd = "cd {dir} && {svn} st | awk -v r=1 '$2 ! ~ /deploy/ {{ print $2; r=0 }} END {{ r || print \":\" }}' | xargs {svn} revert && {svn} up -r {revno}".format(**kwargs)
Я внес некоторые изменения в ваш оригинал:
- Переместил логику
grep
внутри awk
, как предложил @tripleee. Обратите внимание, что поскольку grep
hack больше не нужен, больше нет необходимости обертывать внутри (...)
- Отбросил
tac
, поскольку я не вижу в нем точки
- Выпало
-r
из svn revert
, потому что я не думаю, что вам это нужно
Ответ 2
Не очень, но, надеюсь, обходной путь.
cmd = 'cd ' + checkout_dir + ' && ' +
'r=$(' svn_command + ' st | ' +
"awk '$2 !~ /^deploy/{print $2}' | tac) && " +
'test "$r" && ' +
svn_command + ' revert -R $r && ' +
svn_command + ' up -r ' + options.revision
Я не уверен, что tac
необходим или полезен. Я реорганизовал первый grep
в Awk script для эффективности и эстетических соображений.
Чтобы решить общую проблему "my xargs
отсутствует -r
", суть решения заключается в преобразовании
stuff | xargs -r cmd
в
var=$(stuff)
test "$var" && cmd $var
Без кавычек $var
будет работать только в том случае, если он не содержит имен файлов с пробелами или другими сюрпризами; но тогда голые кости xargs
без расширений GNU страдают от одной и той же проблемы.
Ответ 3
-r
для xargs
не работает в OS X, так как это расширение GNU. Что касается обходного пути, вы должны указать некоторый фиктивный файл, который можно проанализировать с помощью xargs
или не вызывать команду, когда нет аргументов (которые можно проверить ранее).
Метод с использованием временного файла (или любого другого заполнителя):
some_cmd ... | xargs svn revert $(mktemp)
Использование условия в оболочке:
files=$(cd checkout_dir && ... | tac)
if [ -n "$files" ]; then
echo $files | xargs && ...
fi
Смотрите также: Игнорировать пустой результат для xargs
Ответ 4
Bash повторная реализация xargs
с аргументом -r
:
#!/bin/bash
stdin=$(cat <&0)
if [[ $1 == "-r" ]] || [[ $1 == "--no-run-if-empty" ]]
then
# shift the arguments to get rid of the "-r" that is not valid on OSX
shift
# wc -l return some whitespaces, let get rid of them with tr
linecount=$(echo $stdin | grep -v "^$" | wc -l | tr -d '[:space:]')
if [ "x$linecount" = "x0" ]
then
exit 0
fi
fi
# grep returns an error code for no matching lines, so only activate error checks from here
set -e
set -o pipefail
echo $stdin | /usr/bin/xargs [email protected]