Предупреждение :Это взлом. Таким образом, я не даю никаких обещаний относительно его надежности. Тем не менее, менее вероятно, что ваша система будет повреждена, чем альтернатива .
Чтобы сделать это, мы установим новую копию Debian внутри вашей файловой системы, chroot
подключимся к ней для установки некоторых пакетов, а затем создадим своего рода гибридную систему внутри отдельного пространства имен для запуска программы. Для некоторых шагов требуется root-доступ, а для других он должен быть необязательным (, но я еще не разобрался с этим ). Вам понадобится оболочка, debootstrap
, chroot
иgcc
(последняя, потому что нам нужен специальный инструмент ).
Для этого нам понадобится программа с именем debootstrap
. Эта программа, как следует из названия, позволяет вам запустить установку Debian. Вы можете установить его с помощью:
sudo apt-get install debootstrap
Теперь, когда это сделано, мы можем перейти к фактической установке.
sid
на момент написания. chroot.0
и вставил его прямо в свой CWD (, который также является~
). Запустите эту команду:
sudo debootstrap --variant=minbase sid chroot.0
замените sid
на желаемую версию Debian, а chroot.0
на путь к каталогу, который вы хотите использовать.
Вы также можете использовать use --variant=fakeroot
и, возможно, избежать использования sudo
здесь, но это установит множество дополнительных пакетов (, если вы не сможете объединить --variant
с )и может сделать остальные недействительными. ответа из-за проблем с разрешениями.
Пока это выполняется, вы можете читать следующий раздел этого ответа.
Это самая легкая часть. После установки системы вы можете chroot
установить в нее нужные вам пакеты.
chroot
в минимальный экземпляр Debian:
sudo chroot chroot.0
(снова замените chroot.0 на путь, который вы использовали ).
Теперь вы должны находиться в корневой оболочке, где вы можете установить нужные пакеты:
apt install idle-python3.7 python3.7
chroot
, выполнив exit
. Теперь мы можем просто запускать пакеты из chroot
. Но тогда они будут работать как root
и изолированы от вашего домашнего каталога, если только вы не приложите усилий для создания нового пользователя внутри chroot
и настройки привязанной точки монтирования к вашему домашнему каталогу... и в в этот момент это начинает походить на настройку совершенно новой системы. Вместо этого давайте начнем создавать инструменты.
Сохраните это где-нибудь:
#include
#include
#include
#include
int main(int argc, char **argv) {
if (argc < 3) {
printf(
"This is a single-use, disposable program that binds specified directories from\n"
"a chroot's root to the current root.\n"
"\n"
"Argument #1 should be the path to the chroot directory, sans trailing /.\n"
"Subsequent arguments should be paths relative to the root, with preceeding /.\n"
);
return 2;
}
for (int i = 2; i < argc; i += 1) {
char source[PATH_MAX]; /* Not really MAX, but quite big. */
strcpy(&source, argv[1]);
strcat(&source, argv[i]);
if (mount(&source, argv[i],
NULL, MS_BIND,
NULL) == -1) {
return 1;
}
}
return 0;
}
и скомпилируйте его сgcc
:
gcc bindfromchroot.c -o bindfromchroot
Я назвал это bindfromchroot
, потому что это то, что он делает.Причина, по которой мы не можем просто использовать mount --bind
, заключается в том, что необходимо как минимум 2 вызова mount
; один из них будет скрывать mount
, а другой будет скрывать свои библиотеки -, обе из которых прекратят mount
работу в последующий раз и оставят нас с неработающим пространством имен, от которого нам придется exit
избавиться.
Теперь, когда все наши настройки завершены, мы можем запустить некоторые команды, которые, вероятно, следует поместить в сценарий оболочки.
sudo unshare -m su YOUR_USERNAME
или sudo unshare -m su $(id -un)
, чтобы запустить оболочку в отдельном пространстве имен от вашего (или текущего пользователя ). Это «отдельное пространство имен» важно; это означает, что когда мы монтируем части нашего минимального экземпляра Debian поверх основного Debian, изменения будут применяться только к нашей новой оболочке и ее дочерним процессам (, а не ко всем процессам ). Может быть хорошей идеей добавить -c /bin/sh
к команде, потому что bash
отображает раздражающие предупреждающие сообщения о том, что что-то происходит катастрофически неправильно после того, как мы выполним следующий шаг. Запустите инструмент, который вы скомпилировали ранее. Он требует sudo
и на самом деле не говорит вам об ошибках, сохраненных через echo $?
, но выполняет свою работу. Сколько Debian вам нужно связать, зависит от программы, но я настоятельно рекомендую быть как можно более конкретным и не связывать с /etc
, /dev
или /boot
. Чтобы заставить Python 3.7 работать на моей машине, я запустил:
sudo./bindfromchroot chroot.0 /usr /lib
idle-python3.7
. Если это не работает, проверьте сообщения об ошибках, определите, чего не хватает, exit
и повторите попытку с шага 1. Я потратил на это один -вкладыш. Измените соответствующим образом:
sudo unshare -m su wizzwizz4 -c sh -c 'sudo -S./bindfromchroot chroot.0 /usr /lib; idle-python3.7'
Если вы хотите сохранить переменные среды,вместо этого используйте эту версию:
sudo -E unshare -m su wizzwizz4 -mc sh -c 'sudo -ES./bindfromchroot chroot.0 /usr /lib; idle-python3.7'
Вы можете изменить sudo -ES
на sudo -EA
для запуска программы, определенной в переменной окружения SUDO_ASKPASS
, которая может быть графической подсказкой (, такой как та, которая предоставляется с git gui
), если хотите.
Используя GNU awk
, мы можем подойти к проблеме посредством сопоставления имен с индексами полей.
$ awk '
BEGIN {
OFS = FS = "|"
n = split("A-B-C-D-E", x, "-")
for (i=1; i<=n; ++i) h["C_" x[i]] = 2*(i-1) + 3
}
{
# record which out of
# ca/cb/.../ce present
for (i=3; i<NF-2; i+=2) seen[$i] = $(i+1)
# store fields in preparation
# for re-filling them based on seen
nf = split($0, f, FS); $0=""
# fill up the first two..easy does it
$(1) = f[1]
$(2) = f[2]
# recall which fields c_?
# were seen then fill up
# corresponding field and field value
for (var in h) {
i = h[var]
if (var in seen) {
$(i) = var
$(i+1) = seen[var]
} else { $(i) = $(i+1) = ""}
}
# append the last two fields
$(NF+1) = f[nf-1]
$(NF+1) = f[nf]
# above line **NOT** a typo
# clear out the array seen
# for the next iteration
split("", seen, ".")
}1
' file
Результаты:
10|100|C_A|val_18|||||C_D|val_20|||50|60
40|200|C_A|val_5|C_B|val_10|C_C|val_30|C_D|val_90|C_E|val_83|40|45
80|100|||||||||C_E|val_90|50|60
Считайте переменные поля в массивы, распечатайте массивы, получая пустые строки, если они не используются в строке (не забудьте-F '|'
):
BEGIN{
# initialize expected keys for file (value 1 not used)
all_keys["C_A"]=1;
all_keys["C_B"]=1;
all_keys["C_C"]=1;
all_keys["C_D"]=1;
all_keys["C_E"]=1;
}
{
# fill arrays for line
for(i=3;i<NF-1;i+=2) {
key[$i]=$i;
value[$i]=$i+1;
}
# first two fields
printf $1"|"$2"|";
# all variable key/value pairs, occurring on line or not
for (k in all_keys) {
printf key[k]"|"value[k]"|";
}
# last two fields
print $NF-1"|"$NF;
# delete arrays so we don't carry over values into the next line
delete key;
delete value;
}