Я ищу портативный способ экранирования обратной косой черты в строке с помощью awk
.
Например, для GNU и BSD вы должны написать:
echo '\ \\ \\\' | command -p awk '{gsub(/\/,"\\\\"); print}'
Но на других NIX вам придется написать:
echo '\ \\ \\\' | command -p awk '{gsub(/\/,"\\\\\\\\"); print}'
Если у вас нет доступа к AIX/HP-UX/Solaris/etc..., я думаю, что проблема может быть эмулирована с помощью GNU/BSD awk
следующим образом:
echo '\ \\ \\\' | awk '{gsub(/\/, ... ); print}'
echo '\ \\ \\\' | awk --posix '{gsub(/\/, ... ); print}'
где ...
одинаково для обеих команд; оба должны дать:
\\ \\\\ \\\\\\
Эта команда awk
должна быть переносимой:
echo '\ \\ \\\' | awk '{gsub(/\/, "&&")} 1'
Где &
представляет полную совпадающую строку с использованием используемого шаблона регулярного выражения, т. е. /\/
.
Да, это работает! Однако я получаю странный результат на Solaris, я изучаю проблему.
Я думаю, что в libc Solaris есть ошибка. sed 's/\/\\\/g'
и perl -pe 's/\/\\\/g'
оба выводят \\ \\ \\\\
я не могу сказать со 100% уверенностью, работает ли это на чокнутой бахроме, то есть на Solaris
или busybox
awk
, но мой собственный модуль делает это так:
gsub("[\\\\^]", "\\\\&", str)
для экранирования как \\
, так и \^
:
for __ in nawk mawk1 mawk2 'gawk -e'
'gawk -Pe' 'gawk -ce' 'gawk -re' 'gawk -se'
'gawk -ne' 'gawk -Se' 'gawk -Me' 'gawk -MPe'; do
echo " $__ |::::| $( printf '%s' '\\ \\\\ \\\\\\' |
$( printf '%s' "$__" ) ' # either one of ::
function ___(__,_) {
return substr(_ = "\\\\",
gsub("["_ "^]",_ "&",__),_)__
} function ____(_) {
return substr("", gsub(/[\\^]/, "\\\\&",_))_
}
($++NF = ___($!_))^_' FS='\n' OFS=' | '
)"; done | column -s'|' -t
nawk :::: \ \\ \\\ \\ \\\\ \\\\\\
mawk1 :::: \ \\ \\\ \\ \\\\ \\\\\\
mawk2 :::: \ \\ \\\ \\ \\\\ \\\\\\
gawk -e :::: \ \\ \\\ \\ \\\\ \\\\\\
gawk -Pe :::: \ \\ \\\ \\ \\\\ \\\\\\
gawk -ce :::: \ \\ \\\ \\ \\\\ \\\\\\
gawk -re :::: \ \\ \\\ \\ \\\\ \\\\\\
gawk -se :::: \ \\ \\\ \\ \\\\ \\\\\\
gawk -ne :::: \ \\ \\\ \\ \\\\ \\\\\\
gawk -Se :::: \ \\ \\\ \\ \\\\ \\\\\\
gawk -Me :::: \ \\ \\\ \\ \\\\ \\\\\\
gawk -MPe :::: \ \\ \\\ \\ \\\\ \\\\\\
Это работает в gawk и любом awk, совместимом с POSIX:
$ echo '\ \\ \\\' | gawk '{gsub(/\/,"\\\\&"); print}'
\\ \\\\ \\\\\\
$ echo '\ \\ \\\' | gawk --posix '{gsub(/\/,"\\\\&"); print}'
\\ \\\\ \\\\\\
См. https://www.gnu.org/software/gawk/manual/gawk.html#Gory-Details, почему существует разница между поведением POSIX и gawks по умолчанию с некоторыми сериями обратной косой черты в этом контексте и в конкретных таблицах. 9.2 (gawk) и 9.3 (POSIX) показывают, что:
You type sub() sees sub() generates
\\\\& \\& A literal ‘\’, followed by the matched text
как использовано в приведенном выше sub()
s, экранирует строку в POSIX и GNU awk.
Обратите внимание, что выше показано, как экранировать любую совпадающую строку, а не только как экранировать \
:
$ echo 'X XX XXX' | gawk '{gsub(/X/,"\\\\&"); print}'
\X \X\X \X\X\X
$ echo 'X XX XXX' | gawk --posix '{gsub(/X/,"\\\\&"); print}'
\X \X\X \X\X\X
$ echo '[ [[ [[[' | gawk '{gsub(/\[/,"\\\\&"); print}'
\[ \[\[ \[\[\[
$ echo '[ [[ [[[' | gawk --posix '{gsub(/\[/,"\\\\&"); print}'
\[ \[\[ \[\[\[
Спасибо, может пригодится
Awk
здесь невиновен, echo
несовместим между платформами. Совместимой версией echo
является printf
. Попробуй это:
printf '%s\n' '\ \\ \\\' | /usr/bin/awk '{gsub(/\/,"\\\\"); print}'
или это:
printf '\\ \\\\ \\\\\\\n' | /usr/bin/awk '{gsub(/\/,"\\\\"); print}'
Честная оценка; это была проблема с Солярисом. Я не понимаю, почему, хотя оболочка - bash-5.1, поэтому echo не должно ничего делать с обратными косыми чертами o_O
Echo может быть встроенной или отдельной программой (в Aix может быть /usr/ucb/echo, несовместимый с /usr/bin/echo); /bin/sh может быть тире, bash, ksh. Вы можете создать тестовый сценарий для проверки комбинации.
вы рассматривали
FS
способ на Солярисе? ::::::::printf '%s' '\ \\ \\\' | gawk --posix NF=NF FS='\\' OFS='\\\\' ; printf '%s' '\ \\ \\\' | gawk NF=NF FS='\\' OFS='\\\\'
:::::::::::'\\ \\\\ \\\\\\'
::::::::::'\\ \\\\ \\\\\\'