Запуск PHP-скриптов от имени root - опасная практика. Веб-серверы делают все возможное, чтобы предотвратить повышение привилегий, и применяют различные меры, такие как chroot jail. Я считаю, что это может быть причиной ваших проблем.
В частности, dpkg
нуждается в доступе к файлам в /var/lib/dpkg/
, чтобы нормально функционировать. Вы можете проверить, есть ли у вас доступ к этому каталогу из ваших PHP скриптов, например, попытавшись перечислить файлы в нем, или прочитать из /var/lib/dpkg/status
. Если вы этого не делаете (даже при запуске от имени root), значит, вы действительно находитесь в тюрьме. Конечно, вы можете просто отключить jail (как это сделать, зависит от веб-сервера), но я бы не рекомендовал этого делать. Есть причина, по которой это было сделано, и обход механизмов безопасности подвергает вас всевозможным атакам.
Если файлы находятся в текущем рабочем каталоге и их имена соответствуют образцам (одиночный дефис перед числом), следующий POSIX-совместимый конвейер должен работать:
ls | sort -t- -k1,1 -k2,2rn | awk -F- 'k!=$1 {print; k=$1}' | pax -rw /path/to/dir
Компонент awk можно заменить с помощью sort -u, если параметр sort -u является стабильным (так, чтобы для представления этого набора всегда выбиралась первая строка набора). POSIX не требует такой стабильности, но, согласно их руководствам, реализации BSD и GNU {Free, Net, Open} обеспечивают ее. Если вам нравится искушающая судьба:
ls | sort -t- -k1,1 -k2,2rn | sort -mut- -k1,1 | pax -rw /path/to/dir
В любом случае целевой каталог не должен находиться в текущем рабочем каталоге.
Я бы разделил файл на части с разделителями-таблицами для более надежного и настраиваемого разбора имен файлов, затем использовал awk для поиска наивысшего ранга каждой из них и создания отчета. Сначала попробуйте каждую часть конвейера, прежде чем переходить к следующей!
find DIR -type f <other find criteron> -print |
perl -lne 'print join("\t",(/^(.*?-)(\d+)(\.\w+)$/))' |
awk -F\\t '$2 > f[$1] { f[$1]=$2;e[$1]=$3; } END { for (k in f) { print k f[k] e[k] }}' |
xargs cp -t <desination_directory>
Сценарий awk помещает каждое имя файла в ассоциированную запись массива, всегда сохраняя самый высокий найденный ранг. Расширение хранится в собственном массиве. После обработки всех входных данных выводятся все записи массива, по одной в строке. Строка xargs cp -t
копирует все файлы в указанный вами каталог.
Есть еще один метод, который не будет работать очень хорошо, если числа больше 9 и не имеют 0-заполнения. Этот метод сортирует файлы лексикографически, затем при разборе списка первая часть меняется, используется самое последнее встреченное имя файла. Когда имена файлов выглядят следующим образом, это не сработает:
file-9.txt
file-10.txt
потому что файл-10.txt появится раньше файла-9. Приведенный выше сценарий awk выполняет численное сравнение.
ВНИМАНИЕ: Имена файлов с табуляцией и новыми строками приведут к тому, что эта программа заглохнет.
CAVEAT 2: Если возможно несколько расширений на префикс имени файла, нам придется внести некоторые изменения, чтобы сделать это правильно.
Если pwd является исходным dir
cp -t /path_to_destination $(
ls -v *[0-9].txt |
sed '$b;N;/^\(.*\)[0-9]\+\.txt\n\1[0-9]\+\.txt/!P;D')
ПРИМЕЧАНИЕ: Если в именах файлов есть пробелы, то для правильной работы их следует предварительно экранировать. + см. другие ограничения в комментариях Stéphane Chazelas
Это не ответ командной строки, как таковой, но если предположить, что у вас есть bash
версии >= 4, то вот сценарий bash, который собирает все файлы *.txt, определяет их нумерованный суффикс, затем сохраняет самый высокий из увиденных суффиксов в ассоциативный массив (индексированный по базовой части имени файла перед нумерованным суффиксом). Затем выводит образец команды cp
для каждого имени файла с самым высоким суффиксом.
Отрегулируйте назначение "somedir" по мере необходимости.
#!/bin/bash
declare -A highest
for f in *.txt
do
base=${f%%.txt}
prefix=${base%-*}
postfix=${base/$prefix-/}
if [[ ${highest[$prefix]} -lt $postfix ]]
then
highest[$prefix]=$postfix
fi
done
for prefix in "${!highest[@]}"
do
escaped=${prefix//\"/\\\"}
printf "cp -- \"%s\" somedir/\n" "$escaped-${highest[$prefix]}.txt"
done
В каталоге с этими файлами:
-dash-1.txt
-dash-2.txt
double"quote-3.txt
file'here-1.txt
filetwo'here'-2.txt
name_file-1.txt
name_file-2.txt
name_file-3.txt
somefile-5.txt
somefile-60.txt
some_other_file-1.txt
some_other_file-2.txt
space file-1.txt
space file-2.txt
Вывод (отсортированный вручную, для более удобного чтения):
cp -- "-dash-2.txt" somedir/
cp -- "double\"quote-3.txt" somedir/
cp -- "file'here-1.txt" somedir/
cp -- "filetwo'here'-2.txt" somedir/
cp -- "name_file-3.txt" somedir/
cp -- "somefile-60.txt" somedir/
cp -- "some_other_file-2.txt" somedir/
cp -- "space file-2.txt" somedir/
files=(*)
mapfile -t prefixes < <(printf "%s\n" "${files[@]%-*}" | sort -u)
for p in "${prefixes[@]}"; do ls -v "$p"* | tail -1; done
name_file-3.txt
some_other_file-2.txt
А затем скопировать их в другой каталог:
for ...; done | xargs cp -t /destination/directory
С zsh
:
typeset -A greatest
for f (*-*(n)) greatest[${f%-*}]=$f
cp -- $greatest /destination
* - * (n)
: нескрытые файлы, имена которых содержат -
( * - *
), отсортировано численно ( (n)
квалификатор glob). $ {f% - *}
: часть имени файла до самого правого -
(или до конца, если нет -
). $ maximum
: расширяется до непустых значений ассоциативных массивов. Таким образом, здесь для файлов с одним и тем же корнем будет расширен только файл с наибольшим номером.