Запустив systemctl cat keyboard-setup.service
, вы можете увидеть его определение:
# /lib/systemd/system/keyboard-setup.service
[Unit]
Description=Set the console keyboard layout
DefaultDependencies=no
Before=local-fs-pre.target
Wants=local-fs-pre.target
ConditionPathExists=/bin/setupcon
[Service]
Type=oneshot
ExecStart=/lib/console-setup/keyboard-setup.sh
RemainAfterExit=yes
[Install]
WantedBy=sysinit.target
Таким образом, он работает /lib/console-setup/keyboard-setup.sh
, но только если /bin/setupcon
существует.
/lib/console-setup/keyboard-setup.sh
тоже довольно просто:
#!/bin/sh
if \
[ -x /etc/console-setup/cached_setup_keyboard.sh ] \
&& /etc/console-setup/cached_setup_keyboard.sh
then
:
else
if [ -f /etc/default/locale ]; then
# In order to permit auto-detection of the charmap when
# console-setup-mini operates without configuration file.
. /etc/default/locale
export LANG
fi
setupcon -k
fi
Значение:
/etc/console-setup/cached_setup_keyboard.sh
существует и работает без ошибок, этот скрипт ничего не делает, кроме запуска этого скрипта. setupcon -k
, но если /etc/default/locale
существует, она считывается и сначала экспортируется переменная LANG. По крайней мере, в моей системе /etc/console-setup/cached_setup_keyboard.sh
существует и выглядит так:
#!/bin/sh
if [ -f /run/console-setup/keymap_loaded ]; then
rm /run/console-setup/keymap_loaded
exit 0
fi
kbd_mode '-u' < '/dev/tty1'
kbd_mode '-u' < '/dev/tty2'
kbd_mode '-u' < '/dev/tty3'
kbd_mode '-u' < '/dev/tty4'
kbd_mode '-u' < '/dev/tty5'
kbd_mode '-u' < '/dev/tty6'
loadkeys '/etc/console-setup/cached_UTF-8_del.kmap.gz' > '/dev/null'
Значение:
/run/console-setup/keymap_loaded
существует (, указывающий, что раскладка клавиатуры консоли уже была загружена в ранней -загрузочной initramfs ), файл очищается, и сценарий больше ничего не делает, выходя без ошибки. Исходя из этого, вы можете попробовать:
/etc/console-setup/cached_setup_keyboard.sh
и /etc/default/locale
на наличие повреждений или содержания чего-либо -занимает больше времени, чем обычно /etc/console-setup/cached_setup_keyboard.sh
не существует, вы можете попробовать создать аналогичный моему примеру выше (он может быть создан с помощью какого-либо инструмента настройки клавиатуры с графическим интерфейсом, и используемые команды могут быть быстрее, чемsetupcon -k
)/etc/console-setup/cached_setup_keyboard.sh
существует, вы можете попытаться временно сделать его неисполняемым -,загрузка системы и тестирование клавиатуры, чтобы увидеть, можно ли использовать раскладку и быстрее ли путь выполнения через setupcon -k
, чем текущий путь KEYMAP=y
в /etc/initramfs-tools/initramfs.conf
и запустите update-initramfs -u
и посмотрите, ускорит ли это работу, загрузив раскладку в initramfs и заставив keyboard-setup.service
быть по существу обойденным Использование двойных кавычек решает наиболее распространенные проблемы , но не решает все. В вашем случае двойные кавычки защищают от нежелательного расширения в локальной оболочке, но тогда ваша команда ssh
вставляет имя файла непосредственно во фрагмент оболочки без защиты, и rsync делает то же самое под капотом для имен удаленных файлов, переданных на его командная строка¹. То есть, если DEST_PATH
равно /path/with three spaces
, вы выполняете команду
mkdir -p /path/with three spaces/subdir1 /path/with three spaces/subdir2
на удаленной машине. Двойные кавычки вокруг $DEST_PATH
гарантируют, что оболочка, в которой выполняется ваш скрипт, не разделит значение необоснованно, но тогда пробелы имеют смысл в удаленной оболочке.
Наивное использование вложенных кавычек не решает проблему. Например, ssh -i key 10.10.10.10 mkdir -p "'${DEST_PATH}/subdir1'" "'${DEST_PATH}/subdir2'"
будет работать с именами файлов с пробелами, но имена файлов, содержащие '
, не будут работать (и могут быть уязвимостью удаленного выполнения команды, если злоумышленник контролирует значениеDEST_PATH
).
Самый простой выход — запустить sshfs и рассматривать все как локальные пути. Если вам никогда не нужно передавать имена файлов в командах ssh
или rsync
, вам не нужно беспокоиться о заключении этих имен в кавычки. Однако sshfs не всегда удобна в управлении и не обеспечивает эффективного обновления больших файлов с помощью rsync.
Если простой способ вам не подходит, нужно указать значение DEST_PATH
в кавычках. То есть вам нужно изменить /path/with three spaces
на что-то вроде '/path/with three spaces'
или /path/with\ three\ \ spaces
.
set_quoted () {
raw="$1"
quoted=
while case "$raw" in *\'*) true;; *) false;; esac; do
quoted="$quoted'\\''${raw%%\'*}"
raw="${raw#*\'}"
done
quoted="'$quoted$raw'"
}
set_quoted "$DEST_PATH"; quoted_DEST_PATH="$quoted"
ssh -i key 10.10.10.10 mkdir -p "${quoted_DEST_PATH}/subdir1" "${quoted_DEST_PATH}/subdir2"
rsync "${SOURCE_PATH}" "$DEST_HOST:${quoted_DEST_PATH}/subdir1"
¹ У Rsync нет проблем с произвольными именами файлов в рекурсии или в локальных файлах. Но он передает аргументы командной строки, которые являются именем удаленного файла, в удаленную оболочку, которая расширяет их.
Если у вас есть система GNU, ваш printf
поддерживает %q
, что позволяет повторно использовать аргумент в качестве ввода оболочки.
Так что можно сделать
DEST_PATH_ESC="$(printf "%q" "$DEST_PATH")
ssh -i key 10.10.10.10 mkdir -p "${DEST_PATH_ESC}/subdir1" "${DEST_PATH_ESC}/subdir2"
rsync "${SOURCE_PATH}" "$DEST_HOST:${DEST_PATH_ESC}/subdir1" # not sure if you need it here
Проверим:
a="some complicated thing with spaces
and such"
b=$(printf "%q" "$a")
echo "$b"
и получаем
$'some complicated thing with spaces\nand such'
Так что это должно быть вполне безопасно не только для пробелов, но и для новых строк.