Первая ссылка, которая обратится к, является Драйверами устройств Linux (доступный и онлайн и в книжной форме), особенно глава 15, которая имеет раздел по теме.
В идеальном мире каждый компонент системы смог бы отобразить всю память, к которой он когда-либо должен получать доступ. И дело обстоит так для процессов на Linux и большинстве операционных систем: 32-разрядный процесс может только получить доступ немного меньше, чем 2^32 байты виртуальной памяти (на самом деле приблизительно 3 ГБ на типичном Linux 32-разрядная архитектура). Это становится трудным для ядра, которое должно смочь отобразить полную память процесса, системный вызов которого это выполняет, плюс целая физическая память, плюс любое другое устройство с отображенной памятью.
Таким образом, когда 32-разрядное ядро должно отобразить больше чем 4 ГБ памяти, оно должно быть скомпилировано с поддержкой верхней памяти. Верхняя память является памятью, которая постоянно не отображается в адресном пространстве ядра. (Низкая память является противоположным: это всегда отображается, таким образом, можно получить доступ к нему в ядре просто путем разыменования указателя.)
При доступе к верхней памяти из кода ядра необходимо звонить kmap
во-первых, для получения указателя из структуры данных страницы (struct page
). Вызов kmap
работы, является ли страница в высокой или низкой памяти. Существует также kmap_atomic
который добавил ограничения, но более эффективен на многопроцессорных машинах, потому что это использует блокировку с более прекрасными зернами. Указатель, полученный через kmap
ресурс: это израсходовало адресное пространство. После того как Вы закончили с ним, необходимо звонить kunmap
(или kunmap_atomic
) освободить тот ресурс; затем указатель больше не действителен, и к содержанию страницы нельзя получить доступ, пока Вы не звоните kmap
снова.
Используйте sed следующим образом:
$ echo "foobarbazblargblurg" | sed 's/.\{4\}/& /g'
foob arba zbla rgbl urg
Я собираюсь ответить, только вставляя пробелы как требуется, таким образом, пространство появляется, по крайней мере, после каждых 4 символов на строке; не уверенный, какой путь Вы хотите обработать этот случай. Например, учитывая вход "aa bbccdd", Вы произвести "aa bbcc dd", а не "aa b bccd d".
Я использую Perl для предвидения, но я не очень знаком с Perl в целом, таким образом, могут быть необходимые тонкие настройки:
$ echo "foobarbazblargblurg" | perl -wp -e 's/[^ ]{4}(?=[^\n ])/$& /g'
foob arba zbla rgbl urg
$ echo 'aa bbccdd' | perl -wp -e 's/[^ ]{4}(?=[^\n ])/$& /g'
aa bbcc dd
# not 'aa b bccd d'!
$ echo 'some input' | perl -wp -e 's/[^ ]{4}(?=[^\n ])/$& /g'
some inpu t
# not 'some inp ut'!
$ echo $'aabb\nc cddee' | perl -wp -e 's/[^ ]{4}(?=[^\n ])/$& /g' |
> while read; do echo "${REPLY}x"; done
aabbx
c cdde ex
# no spaces added at the end of the first line (while loop to add to the end of
# the line and show this)
Вы можете использовать следующий простой пример:
$ echo "foobarbazblargblurg" | fold -w4 | paste -sd' ' -
foob arba zbla rgbl
Вот пример использования grep
и xargs
:
$ echo "foobarbazblargblurg" | grep -o .... | xargs
foob arba zbla rgbl
Только в bash, без внешних команд:
str="foobarbazblargblurg"
[[ $str =~ ${str//?/(.)} ]]
printf "%s%s%s%s " "${BASH_REMATCH[@]:1}"
или в однотрубном -исполнении:
echo foobarbazblargblurg |
{ IFS= read -r str; [[ $str =~ ${str//?/(.)} ]]; \
printf "%s%s%s%s " "${BASH_REMATCH[@]:1}"; }
Это работает следующим образом: каждый символ строки преобразуется в " (. )" для сопоставления с регулярным выражением и захвата с помощью =~
, а затем просто выводится захваченное выражение из массива BASH_REMATCH[]
, сгруппированное как требуется. Начальные/конечные/промежуточные пробелы сохраняются, удалите кавычки вокруг "${BASH_REMATCH[@]:1}"
, чтобы опустить их.
Здесь он обернут в функцию, которая будет обрабатывать свои аргументы или читать stdin, если аргументов нет:
function fmt4() {
while IFS= read -r str; do
[[ $str =~ ${str//?/(.)} ]]
printf "%s%s%s%s " "${BASH_REMATCH[@]:1}"
done < <( (( $# )) && printf '%s\n' "$@" || printf '%s\n' $(< /dev/stdin) )
}
$ echo foobarbazblargblurg | fmt4
foob arba zbla rgbl urg
Вы можете легко параметризовать количество, чтобы соответствующим образом настроить строку формата.
Добавлен пробел в конце, используйте два printf
вместо одного, если это проблематично:
printf "%s%s%s%s" "${BASH_REMATCH[@]:1:4}"
(( ${#BASH_REMATCH[@]} > 5 )) && printf " %s%s%s%s" "${BASH_REMATCH[@]:5}"
Первый printf
печатает (до )первых 4 символов, второй условно печатает все остальные (, если есть ), с пробелом в начале для разделения групп. Тест для 5 элементов, а не 4 для учета нулевого элемента.
Примечания:
printf
%c
можно использовать вместо %s
,%c
(возможно, )проясняет намерение, но это небезопасно для многобайтовых -символов. Если ваша версия bash на это способна, все вышеперечисленное безопасно для многобайтовых символов -. printf
повторно использует свою строку формата до тех пор, пока у нее не закончатся аргументы, поэтому она просто поглощает 4 аргумента за раз и обрабатывает конечные аргументы (, поэтому не требуется крайних случаев, в отличие от некоторых других ответов здесь которые, возможно, неверны)BASH_REMATCH[0]
— это вся совпадающая строка, поэтому вывод только с индекса 1 printf -v myvar...
вместо этого для сохранения в переменнуюmyvar
(с учетом обычного чтения -поведение цикла/подоболочки)printf "\n"
Вы можете заставить вышеописанное работать в zsh
, если вы используете массив match[]
вместо BASH_REMATCH[]
,и вычтите 1 из всех индексов, поскольку zsh
не сохраняет элемент 0 со всем совпадением.
Только с zsh
:
str=foobarbazblargblurg
set -o extendedglob
printf '%s\n' ${str//(#m)????/$MATCH }
Или
printf '%s%s%s%s ' ${(s::)str}
только с ksh93
:
printf '%s\n' "${str//????/\0 }"
Только с любой оболочкой POSIX (Также избегайте завершающего пробела, если длина ввода кратна 4):
out=
while true; do
case $str in
(?????*)
new_str=${str#????}
out=$out${str%"$new_str"}' '
str=$new_str
;;
(*)
out=$out$str
break
esac
done
printf '%s\n' "$out"
Теперь это для символов . Если вы хотите сделать это, например, на графемных кластерах (, сломать Stéphane
, записанное как $'Ste\u0301phane'
, как Stép hane
, а не Ste phan e
), с помощьюzsh
:
set -o rematchpcre
str=$'Ste\u301phane' out=
while [[ $str =~ '(\X{4})(.+)' ]] {
out+="$match[1] " str=$match[2]
}
out+=$str
printf '%s\n' $out
С помощью ksh93 вы также можете разбивать по ширине отображения, что будет работать для Stéphane
выше, но также может помочь, когда используются некоторые другие виды символов нулевой -ширины или двойной -ширины :
str=$'Ste\u301phane' out=
while
start=${ printf %L.4s. "$str"; }
start=${start%.}
[ "$start" != "$str" ]
do
out+="$start " str=${str#"$start"}
done
out+=$str
printf '%s\n' "$out"
sed
Я попробовал сначала, я мог ударить меня. – xenoterracide 17.01.2011, 16:29