J'ai tourné en rond avec ça. J'étais frustré par la portabilité des octets nuls. Cela ne me convenait pas qu'il n'y avait aucun moyen fiable de les manipuler dans une coquille. J'ai donc continué à chercher. La vérité est que j'ai trouvé plusieurs façons de le faire, dont seulement quelques-unes sont mentionnées dans mon autre réponse. Mais les résultats ont été au moins deux fonctions shell qui fonctionnent comme ceci:
_pidenv ${psrc=$$} ; _zedlmt <$near_any_type_of_file
Je vais d'abord parler de la \0
délimitation. C'est en fait assez facile à faire. Voici la fonction:
_zedlmt() { od -t x1 -w1 -v | sed -n '
/.* \(..\)$/s//\1/
/00/!{H;b};s///
x;s/\n/\\x/gp;x;h'
}
Fondamentalement od
prend stdin
et écrit à son stdout
chaque octet qu'il reçoit en hexadécimal une par ligne.
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
Je parie que vous pouvez deviner quel est le \0null
bon, non? Écrit comme ça, il est facile à manipuler avec tout sed
. sed
enregistre simplement les deux derniers caractères de chaque ligne jusqu'à ce qu'il rencontre une valeur nulle à quel point il remplace les sauts de ligne intermédiaires par printf
un code de format convivial et imprime la chaîne. Le résultat est un \0null
tableau délimité de chaînes d'octets hexadécimales. Regardez:
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
.
J'ai expliqué ce qui précède pour tee
que vous puissiez voir à la fois la sortie de la substitution de commande et le résultat du printf
traitement de. J'espère que vous remarquerez que le sous-shell n'est pas cité non plus, mais qu'il est printf
toujours divisé uniquement au niveau du \0null
délimiteur. Regardez:
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
.
Aucune citation sur cette extension non plus - peu importe si vous la citez ou non. Cela est dû au fait que les valeurs de morsure ne sont pas séparées, à l'exception de la ligne \n
électronique générée pour chaque fois qui sed
imprime une chaîne. Le fractionnement de mots ne s'applique pas. Et c'est ce qui rend cela possible:
_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
La fonction ci-dessus utilise _zedlmt
soit ${pcat}
un flux préparé de code d'octet pour l'approvisionnement de l'environnement de tout processus qui peut être trouvé dans /proc
, soit directement .dot
${psrc}
le même dans le shell actuel, ou sans paramètre, pour afficher une sortie traitée de celui-ci vers le terminal comme set
ou le printenv
fera. Tout ce dont vous avez besoin est d'un $pid
- n'importe quel/proc/$pid/environ
fichier lisible fera l'affaire.
Vous l'utilisez comme ceci:
#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}
Mais quelle est la différence entre convivial et sourcable ? Eh bien, la différence est ce qui rend cette réponse différente de toutes les autres ici - y compris la mienne. Toutes les autres réponses dépendent du shell citant d'une manière ou d'une autre pour gérer tous les cas de bord. Cela ne fonctionne tout simplement pas si bien. Croyez-moi, j'ai ESSAYÉ. Regardez:
_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")
AUCUNE quantité de caractères géniaux ou de guillemets contenus ne peut casser cela car les octets de chaque valeur ne sont évalués qu'au moment même où le contenu est recherché. Et nous savons déjà que cela a fonctionné comme valeur au moins une fois - il n'y a pas de protection d'analyse ou de citation nécessaire ici car il s'agit d'une copie octet par octet de la valeur d'origine.
La fonction évalue d'abord les $var
noms et attend que les vérifications soient terminées avant de se .dot
procurer le here-doc qui l'a alimenté sur le descripteur de fichier 3. Avant de le rechercher, c'est à quoi il ressemble. C'est infaillible. Et POSIX portable. Eh bien, au moins la gestion \ 0null est POSIX portable - le système de fichiers / process est évidemment spécifique à Linux. Et c'est pourquoi il y a deux fonctions.
. <(xargs -0 bash -c 'printf "export %q\n" "$@"' -- < /proc/nnn/environ)
, qui gérera également les variables avec des guillemets correctement.