Параметр Bash, позволяющий при подстановке команд сохранять завершающие символы новой строки

Я не эксперт по mdadm, но, предполагая необработанные данные только со смещением, вы правы, поскольку вы можете изменить таблицу разделов для доступа к разделу как таковому. Вероятно, вам нужно удалить раздел, а затем создать новый раздел в нужном месте. MBR является автономным, никакие данные не будут записаны в сам раздел (, это верно только для первичных разделов ).

Альтернативно, вы можете обернуть блочное устройство петлевым устройством, начиная с заданного смещения. Сообщается, что смещение составляет 2048 секторов, что эквивалентно 2048 · 512 = 1048576 байт.

offset=1048576
losetup -f /dev/sdb3 -o $offset

Затем смонтируйте только что созданное блочное устройство контура (, обычно/dev/loop0).

Или используя крепление напрямую:

mount -o loop,ro,offset=$offset /dev/sdb3 /mountpoint

(roдобавлено по соображениям безопасности во время экспериментов.)

1
28.08.2020, 06:45
2 ответа

Нет возможности сделать это напрямую (, насколько я знаю ), но вы можете подделать это, добавив защитный символ новой строки, не являющийся -в подстановке команды, а затем удалив его впоследствии:

var=$(somecommand; echo x)    # Add an "x" (and one newline that command
                              # substitution will remove) *after* the
                              # newline(s) we want to protect

var=${var%x}    # Remove the "x" from the end

Обратите внимание, что статус выхода somecommandтеряется в процессе, так как и echo x, и var=${var%x}обычно устанавливают статус (на 0 ). Если вам нужно сохранить его до конца, вам нужно добавить немного жонглирования (с кредитом на Кусалананду):

var=$(somecommand; err=$?; echo x; exit "$err")    # Make the subshell
                                                   # exit with somecommand's
                                                   # status
commandstatus=$?    # Preserve the exit status of the subshell
var=${var%x}
# You can now test $commandstatus to see if the command succeeded

Обратите внимание, что обе переменные errи commandstatusхранят статус завершения команды, но они не являются избыточными, поскольку errсуществует только в подоболочке, созданной $( ), а commandstatusсуществует только в родительская оболочка. Вы можете использовать одно и то же имя для обоих, но это может внести путаницу.

Кстати, если вам не нужно сохранять статус до тех пор, пока не будет обрезан "x", вы можете пропустить часть commandstatus:

if var=$(somecommand; err=$?; echo x; exit "$err"); then
    # somecommand succeeded; proceed with processing
    var=${var%x}
    dosomethingwith "$var"
else
    echo "somecommand failed with exit status $?" >&2
fi
3
18.03.2021, 23:09

Единственными известными мне оболочками, в которых есть подстановка команд, которой можно запретить удаление завершающих символов новой строки, являютсяrc(оболочка Unix V10 и plan9, а также общедоступный клон Байрона Ракитциса и его производные, такие как esилиakangafish.

Вrc-подобно раковинам,

var = `{somecommand}

Сохраняет $ifsслов с разделителями в выводе somecommandв $varпеременных (, а переменные представляют собой массивы/списки вrc).

С пустыми $ifs, (ifs = ()), которые сохраняют выходные данные как есть. Разделители также можно указать с помощью ``(separators){somecommand}, поэтому:

var = ``(){somecommand}

Но rc/ es/ akangaне очень похожи на Борна -.

Кроме того, обычно требуется удалить один символ новой строки.

Например, в:

dirname=$(dirname -- "$file")

Вы хотите удалить символ новой строки, добавленный dirname, но не те, которые могут быть в конце каталога $file.

rcне имеет для этого встроенного оператора. Вам понадобится:

dirname = ``(){dirname -- $file | head -c -1}

(нет в стандартеhead). В esвы можете использовать оператор извлечения шаблона ~~:

.
nl = '
'
dirname = <={ ~~ ``(){dirname -- $file} *$nl }

Что едва ли более разборчиво (, хотя может быть превращено в функцию ).

Подстановка команды оболочки fishразбивает вывод на составляющие строки.

set var (somecommand)

Сохраняет строки вывода somecommandв массив $var(, а пустые строки сохраняются даже в конце вывода ).

Если вы установите $IFSна пустой список или одну пустую строку, это разделение будет отключено, и из конца вывода (будет удалено до одного символа новой строки, по крайней мере, в текущих версиях fish, IIRC за прошедшие годы на этом фронте произошло несколько изменений ). Итак,

begin; set -l IFS; set dir (dirname -- $file); end

является надежным.

Я не знаю ни одной оболочки, подобной Bourne -, которой можно было бы приказать не удалять все завершающие символы новой строки. Такое поведение требуется POSIX, и все оболочки, подобные Bourne -, делают это, даже если не в режиме posix (для тех, у кого есть такой, как bash или zsh ).

В bash4.4+ вместо подстановки командвы также можете использовать readarrayв сочетании с заменой процесса (или конвейером с опцией lastpipeи в не -интерактивных экземплярах):

readarray -td '' var < <(somecommand)

Здесь -d ''означает разбиение на NUL. bashвсе равно не поддерживает сохранение NUL в своих переменных, так что для замены подстановки команд этого будет достаточно.

readarray -t lines < <(somecommand)

Сохраняет эти строки вывода somecommandв массив $lines. Затем вы можете соединить их с новой строкой, чтобы восстановить этот вывод без одного конца новой строки:

IFS=$'\n'
output="${lines[*]}"

Но во всех этих подходах вы теряете статус выхода somecommand.

Чтобы обойти эту неправильную функцию подстановки команд, удаляющую все символы новой строки, распространенной идиомой является добавление не -символа новой строки и удаление его (вместе с одним символ новой строки )впоследствии, как сказал Гордон.

Но чтобы сделать это без потери существующего статуса, вам нужно что-то вроде:

cmdsubst() { # args: var cmd args
  eval "$1"'=$(shift; "$@"; ret=$?; printf.; exit "$ret")'
  eval "$1=\${$1%.}; $1=\${$1%'
'}; return $?"
}

Это похоже на подстановку команд, за исключением того, что удаляется только до одного символа новой строки.

Используется как:

cmdsubst dir dirname -- "$file"

вместо:

dir=$(dirname -- "$file")

Или для более сложных команд:

cmdsubst var eval 'cmd1; for i in a b; do cmd "$i"; done'
1
18.03.2021, 23:09

Теги

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