Как бы вы изящно обработали этот фрагмент, чтобы разрешить пробелы в каталогах?

Запустив 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 ), файл очищается, и сценарий больше ничего не делает, выходя без ошибки.
  • в противном случае первые 6 виртуальных консолей инициализируются в режиме UTF -8 Unicode и загружается файл раскладки.

Исходя из этого, вы можете попробовать:

  • проверка ваших /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быть по существу обойденным
7
19.01.2021, 21:34
2 ответа

Использование двойных кавычек решает наиболее распространенные проблемы , но не решает все. В вашем случае двойные кавычки защищают от нежелательного расширения в локальной оболочке, но тогда ваша команда 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 нет проблем с произвольными именами файлов в рекурсии или в локальных файлах. Но он передает аргументы командной строки, которые являются именем удаленного файла, в удаленную оболочку, которая расширяет их.

4
18.03.2021, 22:36

Если у вас есть система 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'

Так что это должно быть вполне безопасно не только для пробелов, но и для новых строк.

0
18.03.2021, 22:36

Теги

Похожие вопросы