Ответы:
В bash или ksh поместите имена файлов в массив и переберите этот массив в обратном порядке.
files=(/var/logs/foo*.log)
for ((i=${#files[@]}-1; i>=0; i--)); do
bar "${files[$i]}"
done
Приведенный выше код также работает в zsh, если эта ksh_arraysопция установлена (он находится в режиме эмуляции ksh). В zsh есть более простой метод, который заключается в изменении порядка совпадений с помощью квалификатора glob:
for f in /var/logs/foo*.log(On); do bar $f; done
POSIX не включает в себя массивы, поэтому, если вы хотите быть переносимым, ваш единственный способ сохранить массив строк - это позиционные параметры.
set -- /var/logs/foo*.log
i=$#
while [ $i -gt 0 ]; do
eval "f=\${$i}"
bar "$f"
i=$((i-1))
done
iи f; просто выполните shift, используйте $1для вашего звонка barи протестируйте [ -z $1 ]в своем while.
[ -z $1 ]ни [ -z "$1" ]полезные тесты (что , если параметр был *, или пустая строка?). И в любом случае они здесь не помогают: вопрос в том, как сделать цикл в обратном порядке.
Попробуйте это, если только вы не считаете разрывы строк «прикольными символами»:
ls /var/logs/foo*.log | tac | while read f; do
bar "$f"
done
fв моей ситуации. Этот ответ, тем не менее, действует в качестве замены для обычной forлинии.
Если кто-то пытается выяснить, как отменить итерацию в списке строк, разделенных пробелами, это работает:
reverse() {
tac <(echo "$@" | tr ' ' '\n') | tr '\n' ' '
}
list="a bb ccc"
for i in `reverse $list`; do
echo "$i"
done
> ccc
> bb
> a
tacявляется частью GNU coreutils. Но ваше решение тоже хорошее.
tac. Хотя по количеству tacответов здесь нет, я думаю, что, возможно, OSX не имеет TAC. В этом случае используйте какой-либо вариант решения @ arp - это легче понять в любом случае.
find /var/logs/ -name 'foo*.log' -print0 | tail -r | xargs -0 bar
Должен работать так, как вы хотите (это было протестировано на Mac OS X, и у меня есть предупреждение ниже ...).
Со страницы руководства для поиска:
-print0
This primary always evaluates to true. It prints the pathname of the current file to standard output, followed by an ASCII NUL character (charac-
ter code 0).
По сути, вы находите файлы, соответствующие вашей строке + glob, и заканчиваете каждый символом NUL. Если ваши имена файлов содержат символы новой строки или другие странные символы, команда find должна с этим справиться.
tail -r
принимает стандартный ввод через канал и переворачивает его (обратите внимание, что все вводимые данные tail -rпечатаются в стандартный вывод, а не только последние 10 строк, что является стандартным значением по умолчанию. для получения дополнительной информации).man tail
Затем мы передадим это xargs -0:
-0 Change xargs to expect NUL (``\0'') characters as separators, instead of spaces and newlines. This is expected to be used in concert with the
-print0 function in find(1).
Здесь xargs ожидает увидеть аргументы, разделенные символом NUL, который вы передали findи отменили tail.
Мое предостережение: я читал, что tailэто не очень хорошо для строк с нулевым символом в конце . Это хорошо работало на Mac OS X, но я не могу гарантировать, что это относится ко всем * nixes. Действуй осторожно.
Следует также отметить, что GNU Parallel часто используется в качестве xargsальтернативы. Вы можете проверить это тоже.
Я могу что-то упустить, поэтому другие должны вмешиваться.
tail -r... я делаю что-то не так?
tacв качестве альтернативы, поэтому я бы попробовал вместо этого
tail -rспецифичен для OSX и инвертирует ввод с разделителями новой строки, а не ввод с нулем. Ваше второе решение вообще не работает (вы вводите данные ls, это не важно); нет простого решения, которое могло бы сделать его надежным.
В вашем примере вы перебираете несколько файлов, но я нашел этот вопрос из-за его более общего заголовка, который также может охватывать зацикливание над массивом или реверсирование на основе любого количества порядков.
Вот как это сделать в Zsh:
Если вы перебираете элементы массива, используйте этот синтаксис ( источник )
for f in ${(Oa)your_array}; do
...
done
Oменяет порядок, указанный в следующем флаге; aнормальный порядок массива.
Как сказал @Gilles, Onобратный порядок ваших файлов, например, с my/file/glob/*(On). Это потому, что Onэто «обратный порядок имен ».
Zsh сортировать флаги:
a порядок массиваL длина файлаl количество ссылокm дата модификацииn название^oобратный порядок ( oнормальный порядок)O обратный порядокДля примеров см. Https://github.com/grml/zsh-lovers/blob/master/zsh-lovers.1.txt и http://reasoniamhere.com/2014/01/11/outrageously-useful-tips- в мастер-ваш-Z-оболочка /
Mac OSX не поддерживает tacкоманду. Решение @tcdyl работает, когда вы вызываете одну команду в forцикле. Для всех остальных случаев следующее - это самый простой способ обойти это.
Этот подход не поддерживает наличие новых строк в ваших именах файлов. Основная причина заключается в том, что tail -rсортирует входные данные как разделенные символами новой строки.
for i in `ls -1 [filename pattern] | tail -r`; do [commands here]; done
Однако есть способ обойти ограничение новой строки. Если вы знаете, что ваши имена файлов не содержат определенный символ (скажем, '='), то вы можете использовать trдля замены всех новых строк, чтобы стать этим символом, а затем выполнить сортировку. Результат будет выглядеть следующим образом:
for i in `find [directory] -name '[filename]' -print0 | tr '\n' '=' | tr '\0' '\n'
| tail -r | tr '\n' '\0' | tr '=' '\n' | xargs -0`; do [commands]; done
Примечание: в зависимости от вашей версии tr, он может не поддерживать '\0'как символ. Обычно это можно обойти, изменив локаль на C (но я не помню как именно, так как после исправления однажды она теперь работает на моем компьютере). Если вы получаете сообщение об ошибке и не можете найти обходной путь, то, пожалуйста, опубликуйте его как комментарий, чтобы я мог помочь вам устранить его.
sort -rпередforили отмытьls -r.