самый короткий способ заменить символы в переменной

Попробуйте AVFS. Это - файловая система FUSE, которая позволяет Вам архивы доступа прозрачно. Выполните эту команду раз и навсегда:

mkdir -p ~/.avfs
grep -q "^avfsd $HOME/.avfs " /proc/mounts ||
avfsd ~/.avfs -o auto_cache

AVFS выставляет содержание архива /path/to/foo.zip как каталог ~/.avfs/path/to/foo.zip# (тот же путь, но под точкой монтирования AVFS, и с дополнительным # в конце). Этот дополнительный каталог не появляется в списке ~/.avfs/path/to, необходимо перейти к нему явно.

С auto_cache опция, демон AVFS сохраняет кэш в памяти (и возможно также в /tmp? Я не понимаю политику кэша AVFS.). Экспериментально, с auto_cache опция, AVFS открывает архив каждый раз, когда Вы получаете доступ к файлу в нем, но только читает несколько байтов из файла, не целого файла.

Gvfs, слой виртуальной файловой системы Gnome, обеспечивает более прозрачный доступ к архивам. Я не знаю, может ли это быть подключено коаксиальным кабелем в кэширующееся содержание архива.

18
09.12.2016, 16:55
4 ответа

В bash или zsh это:

OUTPUT="${OUTPUT//[\`\"\']/}"

Обратите внимание, что $ {VAR// ОБРАЗЕЦ} удаляет все экземпляры образца. Дополнительные сведения Расширение параметров bash

Это решение должно быть самым быстрым для коротких последовательностей, поскольку оно не требует запуска каких-либо внешних программ. Однако очень долго последовательности наоборот - лучше использовать выделенный инструмент для текстовых операций, например:

$ OUTPUT="$(cat /usr/src/linux/.config)"

$ time (echo $OUTPUT | OUTPUT="${OUTPUT//set/abc}")
real    0m1.766s
user    0m1.681s
sys     0m0.002s

$ time (echo $OUTPUT | sed s/set/abc/g >/dev/null)
real    0m0.094s
user    0m0.078s
sys     0m0.006s
-121--24038-

Чтобы увидеть общий прогресс с rsync , современные версии (от 3,1,0) имеют опцию -info = progress2 . rsync должен выполняться на том же компьютере, что и исходные файлы (или с NFS), для отображения допустимых значений. Не забудьте также указать параметр -a при копировании системных каталогов.

-121--67428-

Посмотрим. Самое короткое, что я могу придумать, это сдвиг вашего решения tr :

OUTPUT="$(tr -d "\"\`'" <<<$OUTPUT)"

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

OUTPUT="${OUTPUT//[\'\"\`]}"

И sed конечно, хотя это больше с точки зрения символов:

OUTPUT="$(sed s/[\'\"\`]//g <<<$OUTPUT)"

Я не уверен, если вы имеете в виду самую короткую по длине или с точки зрения времени. По длине эти два такие короткие, как он получает (или как я могу получить его в любом случае), когда речь идет об удалении этих конкретных символов. Итак, что быстрее всего? Я проверил, установив переменную OUTPUT в соответствии с тем, что было в вашем примере, но повторил несколько десятков раз:

$ echo ${#OUTPUT} 
4900

$ time tr -d "\"\`'" <<<$OUTPUT
real    0m0.002s
user    0m0.004s
sys     0m0.000s
$ time sed s/[\'\"\`]//g <<<$OUTPUT
real    0m0.005s
user    0m0.000s
sys     0m0.000s
$ time echo ${OUTPUT//[\'\"\`]}
real    0m0.027s
user    0m0.028s
sys     0m0.000s

Как вы видите, tr явно самая быстрая, за ней следует sed . Кроме того, кажется, что использование echo на самом деле немного быстрее, чем использование < < < :

$ for i in {1..10}; do 
    ( time echo $OUTPUT | tr -d "\"\`'" > /dev/null ) 2>&1
done | grep -oP 'real.*m\K[\d.]+' | awk '{k+=$1;} END{print k/NR}'; 
0.0025
$ for i in {1..10}; do 
    ( time tr -d "\"\`'" <<<$OUTPUT > /dev/null ) 2>&1 
  done | grep -oP 'real.*m\K[\d.]+' | awk '{k+=$1;} END{print k/NR}'; 
0.0029

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

echo $OUTPUT | tr -d "\"\`'" 

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

$ for i in {1..10}; do
    ( time OUTPUT=${OUTPUT//[\'\"\`]} ) 2>&1
  done | grep -oP 'real.*m\K[\d.]+' | awk '{k+=$1;} END{print k/NR}'; 
0.0032

$ for i in {1..10}; do
    ( time OUTPUT=$(echo $OUTPUT | tr -d "\"\`'")) 2>&1
  done | grep -oP 'real.*m\K[\d.]+' | awk '{k+=$1;} END{print k/NR}'; 
0.0044

Итак, в заключение, когда вы просто хотите просмотреть результаты, используйте tr , но если вы хотите переназначить переменную, использование последовательности функций манипуляции оболочки быстрее, так как они избегают накладных расходов при выполнении отдельной субоболочки.

22
27.01.2020, 19:45

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

$ OUTPUT=a\'b\"c\`d
$ echo "$OUTPUT"
a'b"c`d

Используйте этот синтаксис: $ {Parameter // Pattern / Strattion} для замены всех вхождений шаблона со строкой.

$ echo "${OUTPUT//\'/x}"
axb"c`d
$ echo "${OUTPUT//\"/x}"
a'bxc`d
$ echo "${OUTPUT//\`/x}"
a'b"cxd
$ echo "${OUTPUT//[\'\"\`]/x}"
axbxcxd
15
27.01.2020, 19:45

В Bash или ZSH это:

OUTPUT="${OUTPUT//[\`\"\']/}"

Обратите внимание, что $ {var // pattern /} удаляет все экземпляры шаблона. Для получения дополнительной информации Расширение параметра Bash

Это решение должно быть самым быстрым для коротких строк, потому что он не включает никаких внешних программ. Однако для очень длинных струн наоборот верно - лучше использовать специальный инструмент для текстовых операций, например:

$ OUTPUT="$(cat /usr/src/linux/.config)"

$ time (echo $OUTPUT | OUTPUT="${OUTPUT//set/abc}")
real    0m1.766s
user    0m1.681s
sys     0m0.002s

$ time (echo $OUTPUT | sed s/set/abc/g >/dev/null)
real    0m0.094s
user    0m0.078s
sys     0m0.006s
12
27.01.2020, 19:45

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

aq() { sh -c 'for a do
       alias "$((i=$i+1))=$a"
       done; alias' -- "$@"
}

Эта оболочка функции цитирует любой аргументированный массив, который вы ей передаете, и увеличивает его вывод на каждый итерабельный аргумент.

Вот он с несколькими аргументами:

aq \
"here's an
ugly one" \
"this one is \$PATHpretty bad, too" \
'this one```****```; totally sucks'

OUTPUT

1='here'"'"'s an
ugly one'
2='this one is $PATHpretty bad, too'
3='this one```****```; totally sucks'

Выводится из тире dash, который обычно выводится в кавычках, как ''''''. bash сделал бы '\''.

Замена подборки одинарных, не белых, ненулевых байтов на другой одинарный байт, вероятно, может быть выполнена быстрее всего в любой оболочке POSIX с $IFS и $*.

set -f; IFS=\"\'\`; set -- $var; printf %s "$*"

OUTPUT

"some ""crazy """"""""string ""here

Там я просто printf, чтобы вы могли его увидеть, но, конечно, если бы я сделал:

var="$*"

... вместо команды printf $var значение было бы тем, что вы видите в выводе там.

Когда я установил -f, я инструктирую оболочку , а не на глобус - в случае, если строка содержит символы, которые могут быть истолкованы как шаблоны глобуса. Я делаю это потому, что синтаксический анализатор оболочки расширяет шаблоны глобусов после , он производит разбиение полей на переменные. Глобус можно включить заново, как set +f. В общем - в скриптах - я нахожу полезным установить мой bang как:

#!/usr/bin/sh -f

А затем на явно включить глобубинг с помощью установки +f на любой строке, которая мне может понадобиться.

Разделение полей происходит на основе символов в $IFS.

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

IFS=\ ; var='      '; printf '<%s>' $var
<>

Но все остальные указаны для оценки к одному полю на одно событие - они не усечены.

IFS=/; var='/////'; printf '<%s>' $var
<><><><><>

Все расширения переменных по умолчанию $IFS - они разделены на отдельные поля в соответствии с $IFS. Когда вы " - процитируете одно, вы переопределяете это свойство массива и оцениваете его как единственную строку.

- так что когда я это сделаю...

IFS=\"\'\`; set -- $var

я устанавливаю массив аргументов оболочки на множество $IFS разделенных полей, сгенерированных расширением $var. При расширении его составные значения для символов, содержащихся в $IFS, являются потерянными - теперь это только разделители полей - это \0NUL.

"$*" - как и другие двузначные расширения переменных - также перекрывают разделение полей в $IFS. Но, , кроме того , заменяет первый байт в $IFS для каждого делимитированного поля в "$@". Так как " было первым значением в $IFS , то все последующие разделители становятся " в "$*". И " тоже не обязательно быть в $IFS, когда вы разделяете его. Вы можете изменить $IFS после set -- $args на другое значение целиком и его новый первый байт будет затем показан для разделителей полей в "$*". Более того, вы можете удалить все их следы полностью, как:

set -- $var; IFS=; printf %s "$*"

OUTPUT

some crazy string here
6
27.01.2020, 19:45

Теги

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