Ответы:
В 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
.