Chodziłem z tym po kółku. Byłem sfrustrowany przenośnością zerowych bajtów. Nie podobało mi się to, że nie było niezawodnego sposobu na obsłużenie ich w skorupce. Więc szukałem dalej. Prawda jest taka, że znalazłem kilka sposobów, aby to zrobić, z których tylko kilka zostało odnotowanych w mojej drugiej odpowiedzi. Ale rezultatem były co najmniej dwie funkcje powłoki, które działają w ten sposób:
_pidenv ${psrc=$$} ; _zedlmt <$near_any_type_of_file
Najpierw porozmawiam o \0
rozgraniczeniu. To jest naprawdę łatwe do zrobienia. Oto funkcja:
_zedlmt() { od -t x1 -w1 -v | sed -n '
/.* \(..\)$/s//\1/
/00/!{H;b};s///
x;s/\n/\\x/gp;x;h'
}
Zasadniczo od
pobiera stdin
i zapisuje do stdout
każdego otrzymanego bajtu w systemie szesnastkowym po jednym w wierszu.
printf 'This\0is\0a\0lot\0\of\0\nulls.' |
od -t x1 -w1 -v
#output
0000000 54
0000001 68
0000002 69
0000003 73
0000004 00
0000005 69
0000006 73
#and so on
Założę się, że możesz zgadnąć, co jest \0null
, prawda? Tak napisane jest łatwe w obsłudze z każdym sed
. sed
po prostu zapisuje dwa ostatnie znaki w każdej linii, aż napotka zero, w którym to miejscu zastępuje nowe znaki pośrednie printf
kodem przyjaznego formatu i wypisuje ciąg. Wynikiem jest \0null
rozdzielona tablica ciągów bajtów szesnastkowych. Popatrz:
printf %b\\n $(printf 'Fewer\0nulls\0here\0.' |
_zedlmt | tee /dev/stderr)
#output
\x46\x65\x77\x65\x72
\x6e\x75\x6c\x6c\x73
\x68\x65\x72\x65
\x2e
Fewer
nulls
here
.
Przetokowałem powyższe, aby tee
można było zobaczyć zarówno wynik działania polecenia, jak i wynik printf
jego przetwarzania. Mam nadzieję, że zauważysz, że podpowłoka faktycznie nie jest cytowana, ale printf
nadal dzieli się tylko na \0null
ograniczniku. Popatrz:
printf %b\\n $(printf \
"Fe\n\"w\"er\0'nu\t'll\\'s\0h ere\0." |
_zedlmt | tee /dev/stderr)
#output
\x46\x65\x0a\x22\x77\x22\x65\x72
\x27\x6e\x75\x09\x27\x6c\x6c\x27\x73
\x68\x20\x20\x20\x20\x65\x72\x65
\x2e
Fe
"w"er
'nu 'll's
h ere
.
Brak cytatów na temat tego rozszerzenia - nie ma znaczenia, czy go zacytujesz, czy nie. Wynika to z tego, że wartości zgryzu są \n
rozdzielane osobno, z wyjątkiem jednej linii ewline generowanej za każdym razem, gdy sed
drukuje łańcuch. Podział słów nie ma zastosowania. I to sprawia, że jest to możliwe:
_pidenv() { ps -p $1 >/dev/null 2>&1 &&
[ -z "${1#"$psrc"}" ] && . /dev/fd/3 ||
cat <&3 ; unset psrc pcat
} 3<<STATE
$( [ -z "${1#${pcat=$psrc}}" ] &&
pcat='$(printf %%b "%s")' || pcat="%b"
xeq="$(printf '\\x%x' "'=")"
for x in $( _zedlmt </proc/$1/environ ) ; do
printf "%b=$pcat\n" "${x%%"$xeq"*}" "${x#*"$xeq"}"
done)
#END
STATE
Powyższa funkcja używa _zedlmt
albo ${pcat}
do przygotowanego strumienia kodu bajtowego do pozyskiwania środowiska dowolnego procesu, który można znaleźć w /proc
, lub bezpośrednio do .dot
${psrc}
tego samego w bieżącej powłoce lub bez parametru, aby wyświetlić przetworzone wyjście tego samego na terminalu, takie jak set
lub printenv
będzie. Wszystko czego potrzebujesz to $pid
- zrobi każdy czytelny /proc/$pid/environ
plik.
Używasz go w ten sposób:
#output like printenv for any running process
_pidenv $pid
#save human friendly env file
_pidenv $pid >/preparsed/env/file
#save unparsed file for sourcing at any time
_pidenv ${pcat=$pid} >/sourcable/env.save
#.dot source any pid's $env from any file stream
_pidenv ${pcat=$pid} | sh -c '. /dev/stdin'
#feed any pid's env in on a heredoc filedescriptor
su -c '. /dev/fd/4' 4<<ENV
$( _pidenv ${pcat=$pid} )
ENV
#.dot sources any $pid's $env in the current shell
_pidenv ${psrc=$pid}
Ale jaka jest różnica między człowiekiem przyjaznym a zasobnym ? Różnica polega na tym, że ta odpowiedź różni się od wszystkich tutaj - w tym mojej drugiej. Każda inna odpowiedź zależy w jakiś sposób od cytowania powłoki w celu obsłużenia wszystkich przypadków krawędzi. Po prostu nie działa tak dobrze. Proszę uwierz mi - SPRÓBOWAŁEM. Popatrz:
_pidenv ${pcat=$$}
#output
LC_COLLATE=$(printf %b "\x43")
GREP_COLOR=$(printf %b "\x33\x37\x3b\x34\x35")
GREP_OPTIONS=$(printf %b "\x2d\x2d\x63\x6f\x6c\x6f\x72\x3d\x61\x75\x74\x6f")
LESS_TERMCAP_mb=$(printf %b "\x1b\x5b\x30\x31\x3b\x33\x31\x6d")
LESS_TERMCAP_md=$(printf %b "\x1b\x5b\x30\x31\x3b\x33\x31\x6d")
LESS_TERMCAP_me=$(printf %b "\x1b\x5b\x30\x6d")
LESS_TERMCAP_se=$(printf %b "\x1b\x5b\x30\x6d")
LESS_TERMCAP_so=$(printf %b "\x1b\x5b\x30\x30\x3b\x34\x37\x3b\x33\x30\x6d")
LESS_TERMCAP_ue=$(printf %b "\x1b\x5b\x30\x6d")
ŻADNA liczba funky znaków lub zawartych cytatów nie może tego zepsuć, ponieważ bajty dla każdej wartości nie są obliczane aż do momentu, gdy zawartość jest pobierana. Wiemy już, że przynajmniej raz działała jako wartość - nie ma tu potrzeby analizy składni ani cytowania, ponieważ jest to kopia bajt po bajcie oryginalnej wartości.
Ta funkcja najpierw ocenia $var
nazwy i czeka na zakończenie kontroli, zanim .dot
sourcing dokona tego tutaj, podając go deskryptorowi pliku 3. Zanim zacznie źródła, tak to wygląda. Jest głupi. I przenośny POSIX. Cóż, przynajmniej obsługa \ 0null jest przenośna POSIX - system plików / process jest oczywiście specyficzny dla Linuksa. I dlatego są dwie funkcje.
. <(xargs -0 bash -c 'printf "export %q\n" "$@"' -- < /proc/nnn/environ)
, który również odpowiednio obsługuje zmienne z cudzysłowami.