Как я вставляю пробел каждые четыре символа в длинной линии?

Первая ссылка, которая обратится к, является Драйверами устройств Linux (доступный и онлайн и в книжной форме), особенно глава 15, которая имеет раздел по теме.

В идеальном мире каждый компонент системы смог бы отобразить всю память, к которой он когда-либо должен получать доступ. И дело обстоит так для процессов на Linux и большинстве операционных систем: 32-разрядный процесс может только получить доступ немного меньше, чем 2^32 байты виртуальной памяти (на самом деле приблизительно 3 ГБ на типичном Linux 32-разрядная архитектура). Это становится трудным для ядра, которое должно смочь отобразить полную память процесса, системный вызов которого это выполняет, плюс целая физическая память, плюс любое другое устройство с отображенной памятью.

Таким образом, когда 32-разрядное ядро должно отобразить больше чем 4 ГБ памяти, оно должно быть скомпилировано с поддержкой верхней памяти. Верхняя память является памятью, которая постоянно не отображается в адресном пространстве ядра. (Низкая память является противоположным: это всегда отображается, таким образом, можно получить доступ к нему в ядре просто путем разыменования указателя.)

При доступе к верхней памяти из кода ядра необходимо звонить kmap во-первых, для получения указателя из структуры данных страницы (struct page). Вызов kmap работы, является ли страница в высокой или низкой памяти. Существует также kmap_atomic который добавил ограничения, но более эффективен на многопроцессорных машинах, потому что это использует блокировку с более прекрасными зернами. Указатель, полученный через kmap ресурс: это израсходовало адресное пространство. После того как Вы закончили с ним, необходимо звонить kunmap (или kunmap_atomic) освободить тот ресурс; затем указатель больше не действителен, и к содержанию страницы нельзя получить доступ, пока Вы не звоните kmap снова.

32
17.01.2011, 16:27
6 ответов

Используйте sed следующим образом:

$ echo "foobarbazblargblurg" | sed 's/.\{4\}/& /g'
foob arba zbla rgbl urg
56
27.01.2020, 19:37
  • 1
    проклиная, который был так близко к sed Я попробовал сначала, я мог ударить меня. –  xenoterracide 17.01.2011, 16:29
  • 2
    Просто любопытный, каков '&', выполняют? О, это - заместитель для 'вещи, что просто соответствовало'. Глупый я. –  Omnifarious 27.08.2012, 08:25
  • 3
    нужно отметить, что это добавляет пространство в конце также, если существует еще один символ в строке, которая не могла бы быть желательной –  Anubis 19.04.2018, 20:07

Я собираюсь ответить, только вставляя пробелы как требуется, таким образом, пространство появляется, по крайней мере, после каждых 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)
2
27.01.2020, 19:37

Вы можете использовать следующий простой пример:

$ echo "foobarbazblargblurg" | fold -w4 | paste -sd' ' -
foob arba zbla rgbl
22
27.01.2020, 19:37

Вот пример использования grep и xargs:

$ echo "foobarbazblargblurg" | grep -o .... | xargs
foob arba zbla rgbl
4
27.01.2020, 19:37

Только в 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 для учета нулевого элемента.

Примечания:

  • shell printf%cможно использовать вместо %s,%c(возможно, )проясняет намерение, но это небезопасно для многобайтовых -символов. Если ваша версия bash на это способна, все вышеперечисленное безопасно для многобайтовых символов -.
  • оболочка printfповторно использует свою строку формата до тех пор, пока у нее не закончатся аргументы, поэтому она просто поглощает 4 аргумента за раз и обрабатывает конечные аргументы (, поэтому не требуется крайних случаев, в отличие от некоторых других ответов здесь которые, возможно, неверны)
  • BASH_REMATCH[0]— это вся совпадающая строка, поэтому вывод только с индекса 1
  • использовать printf -v myvar...вместо этого для сохранения в переменнуюmyvar(с учетом обычного чтения -поведение цикла/подоболочки)
  • при необходимости добавьте printf "\n"

Вы можете заставить вышеописанное работать в zsh, если вы используете массив match[]вместо BASH_REMATCH[],и вычтите 1 из всех индексов, поскольку zshне сохраняет элемент 0 со всем совпадением.

5
27.01.2020, 19:37

Только с 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"
4
27.01.2020, 19:37

Теги

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