Двойная и тройная замена в ударе и zsh

Насколько я знаю, все китайские символы 3 байта длиной при кодировании в UTF-8, нормальном кодировании Unicode на Unix. Но некитайские символы, такие как пробелы и новые строки могут быть другой шириной (основные управляющие символы, а также арабские формы цифры и другие, единственный широкий байт). split утилита только понимает постоянные числа байтов, таким образом, она сократит без разбора неровно.

Необходимо будет использовать более сложный инструмент для разделения каждых 42 символов. Вот отрывок Perl, который должен добиться цели (непротестированный). Обратите внимание, что это - обработки каждый символ одинаково: китайские счетчики символов для 1, новая строка - также.

perl -CDS -e '
    $n = 0;
    while (read STDIN, $buf, 42) {
        open OUT, sprintf("> output-$n.txt") or die;
        print OUT $buf;
        close OUT or die;
        ++$n;
    }'

24
13.04.2017, 15:36
7 ответов

\ должен использоваться для предотвращения расширения $$ (идентификатор текущего процесса). Для тройной замены Вы должны удвоить оценку, так также больше Escape для предотвращения нежелательных расширений в каждой оценке:

#! /bin/bash
l0=value
l1=l0
l2=l1
l3=l2
l4=l3

echo $l0
eval echo \$$l1
eval eval echo \\$\$$l2
eval eval eval echo \\\\$\\$\$$l3
eval eval eval eval echo \\\\\\\\$\\\\$\\$\$$l4
15
27.01.2020, 19:41
  • 1
    все же: l3=l2; eval eval eval echo \\\$\\$\$$l353294 так не точно модульный. –  Profpatsch 15.03.2013, 13:29
  • 2
    Почему я не могу сделать чего-то как eval $(eval echo \$$l2)? Я ненавижу удар, он не имеет абсолютно никакого смысла. –  Profpatsch 15.03.2013, 13:31
  • 3
    @Profpatsch: Добавленный больше примеров. –  choroba 15.03.2013, 13:38
  • 4
    Для получения ожидаемого вывода необходимо выйти из обратной косой черты с другой обратной косой чертой в одинарных левых кавычках: echo `eval echo \\$$VAR` ---------121 А-ч--------122650----, это - n ². Я даже не хочу пытаться добраться, почему это похоже на это. –  Profpatsch 15.03.2013, 13:43
  • 5
    @Profpatsch: Легкий. На каждом шаге, количестве половин обратных косых черт (таким образом, это - 2 ⁿ, на самом деле). –  choroba 15.03.2013, 13:46

Предположим, значение FOO допустимое имя переменной (сказать BAR), eval \$$FOO разделяет значение BAR в отдельные слова, рассматривает каждое слово как подстановочный шаблон и выполняет первое слово результата как команда, передавая другие слова как аргументы. Обратная косая черта перед долларом заставляет его рассматриваться буквально, таким образом, аргумент передал eval встроенный четыре символьных строки $BAR.

${${FOO}} синтаксическая ошибка. Это не делает “двойной замены”, потому что нет такой функции ни в одной из общих оболочек (не с этим синтаксисом так или иначе). В zsh, ${${FOO}} допустимо и двойная замена, но она ведет себя по-другому по сравнению с тем, что Вы хотели бы: это выполняет два последовательных преобразования на значении FOO, оба из которых являются преобразованием идентификационных данных, таким образом, это - просто необычный способ записать ${FOO}.

Если Вы хотите рассматривать значение переменной как переменная, остерегаются заключения в кавычки вещей правильно. Намного легче при установке результата на переменную:

eval "value=\${$FOO}"
6
27.01.2020, 19:41
  • 1
    Установка его столь же переменный, так, чтобы первое слово не использовалось как команда? Человек, этот вид логики трудно схватить. Это - общая проблема, которую я, кажется, имею с ударом. –  Profpatsch 19.03.2013, 15:45

Почему необходимо было бы сделать это?

Можно всегда делать это в несколько этапов как:

eval "l1=\${$var}"
eval "l2=\${$l1}"
...

Или используйте функцию как:

deref() {
  if [ "$1" -le 0 ]; then
    eval "$3=\$2"
  else
    eval "deref $(($1 - 1)) \"\${$2}\" \"\$3\""
  fi
}

Затем:

$ a=b b=c c=d d=e e=blah
$ deref 3 a res; echo "$res"
d
$ deref 5 a res; echo "$res"
blah

FWIW, в zsh:

$ echo ${(P)${(P)${(P)${(P)a}}}}
blah
3
27.01.2020, 19:41
  • 1
    Ха, использование нескольких шагов не произошло со мной до сих пор … странный. –  Profpatsch 24.03.2013, 20:08
  • 2
    Очевидно с моей точки зрения, почему @Profpatsch хочет сделать это. Поскольку это - самый интуитивный способ сделать это. Быть твердым реализовать несколько замен в ударе является другой вещью. –  Nikos Alexandris 26.07.2013, 18:35

Точно так же, как ${$foo} не работает вместо ${(P)foo} в zsh, ни один не делает ${${$foo}}. Просто необходимо указать каждый уровень абстракции:

$ foo=bar
$ bar=baz
$ baz=3
$ echo $foo
bar
$ echo ${(P)foo}
baz
$ echo ${(P)${(P)foo}}
3

Конечно, ${!${!foo}} не работает в bash, потому что bash не позволяет вложенные замены.

2
27.01.2020, 19:41
  • 1
    Спасибо, это хорошо для знания. Позор, который это zsh-только, таким образом, Вы не можете действительно поместить его в сценарий (у всех есть удар, но это не наоборот). –  Profpatsch 24.03.2013, 18:08
  • 2
    я подозреваю zsh устанавливается намного чаще, чем Вы могли бы принять. Это не может быть связано с sh как bash часто (но не всегда), но это может все еще быть доступно для сценариев оболочки. Думайте это как Вы делает Perl или Python. –  chepner 24.03.2013, 18:24
#!/bin/bash

hello=world
echo=hello

echo $echo ${!echo}
10
27.01.2020, 19:41

Решение POSIX

Не заморачиваясь цитированием, вы можете использовать эту функцию для многих уровней косвенности, например:

$ a=b
$ b=c
$ c=d
$ echo $(var_expand $(var_expand $a)
d

Или если у вас больше (!?! )уровней косвенности, которые вы могли бы использовать в цикле.

Предупреждает при подаче:

  • Нулевой ввод
  • Более одного аргумента
  • Не задано имя переменной

# Expand the variable named by $1 into its value. Works in both {ba,z}sh
# eg: a=HOME $(var_expand $a) == /home/me
function var_expand {
  if [ "$#" -ne 1 ] || [ -z "${1-}" ]; then
    printf 'var_expand: expected one argument\n' >&2;
    return 1;
  fi
  eval printf '%s' "\"\${$1?}\""
}
2
27.01.2020, 19:41

{ba,z}sh раствор

Вот функция, которая работает в обоих {ba,z}sh. Я считаю, что он также совместим с POSIX.

Не заморачиваясь с цитированием, вы можете использовать его для многих уровней косвенности, например:

$ a=b
$ b=c
$ c=d
$ echo $(var_expand $(var_expand $a)
d

Или если у вас больше (!?! )уровней косвенности вы можете использовать цикл.

Предупреждает при подаче:

  • Нулевой ввод
  • Не задано имя переменной
# Expand the variable named by $1 into its value. Works in both {ba,z}sh
# eg: a=HOME $(var_expand $a) == /home/me
var_expand() {
  if [ -z "${1-}" ] || [ $# -ne 1 ]; then
    printf 'var_expand: expected one argument\n' >&2;
    return 1;
  fi
  eval printf '%s' "\"\${$1?}\""
}
6
27.01.2020, 19:41

Теги

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