Попробуйте 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, обеспечивает более прозрачный доступ к архивам. Я не знаю, может ли это быть подключено коаксиальным кабелем в кэширующееся содержание архива.
В 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
при копировании системных каталогов.
Посмотрим. Самое короткое, что я могу придумать, это сдвиг вашего решения 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
, но если вы хотите переназначить переменную, использование последовательности функций манипуляции оболочки быстрее, так как они избегают накладных расходов при выполнении отдельной субоболочки.
Вы можете использовать переменную замену :
$ 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
В 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
Если вы просто пытаетесь обработать кавычки для повторного использования оболочки, то вы можете сделать это без их удаления, и это тоже очень просто:
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'
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 "$*"
"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 "$*"
some crazy string here