Sono andato in giro con questo. Ero frustrato dalla portabilità dei byte null. Non mi andava bene che non esistesse un modo affidabile per gestirli in una shell. Quindi ho continuato a cercare. La verità è che ho trovato diversi modi per farlo, solo un paio dei quali sono indicati nella mia altra risposta. Ma i risultati sono stati almeno due funzioni shell che funzionano in questo modo:
_pidenv ${psrc=$$} ; _zedlmt <$near_any_type_of_file
Per prima cosa parlerò della \0
delimitazione. In realtà è abbastanza facile da fare. Ecco la funzione:
_zedlmt() { od -t x1 -w1 -v | sed -n '
/.* \(..\)$/s//\1/
/00/!{H;b};s///
x;s/\n/\\x/gp;x;h'
}
Praticamente od
prende stdin
e scrive su stdout
ogni byte che riceve in esadecimale uno per riga.
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
Scommetto che puoi indovinare qual è il \0null
, giusto? Scritto in questo modo è facile da gestire con qualsiasi sed
. sed
salva solo gli ultimi due caratteri in ogni riga fino a quando non incontra un valore null a quel punto sostituisce le newline intermedie con printf
un codice di formato intuitivo e stampa la stringa. Il risultato è una \0null
matrice delimitata di stringhe di byte esadecimali. Guarda:
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
.
Ho analizzato quanto sopra in tee
modo da poter vedere sia l'output del comando susbstitution che il risultato printf
dell'elaborazione. Spero che noterai che la subshell in realtà non è nemmeno quotata ma è printf
ancora divisa solo dal \0null
delimitatore. Guarda:
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
.
Neanche citazioni su quell'espansione - non importa se la citate o no. Ciò è dovuto al fatto che i valori del morso vengono \n
trasmessi senza separazione, ad eccezione di una ewline generata ogni volta che sed
stampa una stringa. La divisione delle parole non si applica. E questo è ciò che lo rende possibile:
_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
Gli usi funzione sopra _zedlmt
ad sia ${pcat}
un flusso preparato di codice byte per l'ambiente approvvigionamento di qualsiasi processo che può essere trovato in /proc
, o direttamente .dot
${psrc}
lo stesso nella shell corrente, o senza un parametro, per visualizzare un'uscita elaborata stessi al terminale come set
o printenv
volontà. Tutto ciò che serve è un $pid
- qualsiasi/proc/$pid/environ
file leggibile farà.
Lo usi in questo modo:
#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}
Ma qual è la differenza tra umano amichevole e sourcable ? Bene, la differenza è ciò che rende questa risposta diversa dalle altre qui - compresa la mia altra. Ogni altra risposta dipende dalla quotazione della shell in un modo o nell'altro per gestire tutti i casi limite. Semplicemente non funziona così bene. Per favore, credimi, ho provato. Guarda:
_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")
NESSUN numero di caratteri funky o citazioni contenute può interrompere questo perché i byte per ciascun valore non vengono valutati fino all'istante in cui il contenuto viene fornito. E sappiamo già che ha funzionato come valore almeno una volta: qui non è necessaria alcuna protezione di analisi o quotazione perché si tratta di una copia byte per byte del valore originale.
La funzione valuta innanzitutto i $var
nomi e attende che vengano completati i controlli prima di .dot
approvvigionare il here-doc alimentandolo sul descrittore di file 3. Prima che lo generi è come appare. È a prova di folle. E POSIX portatile. Bene, almeno la gestione \ 0null è POSIX portatile - il filesystem / process è ovviamente specifico per Linux. Ed è per questo che ci sono due funzioni.
. <(xargs -0 bash -c 'printf "export %q\n" "$@"' -- < /proc/nnn/environ)
, che gestirà correttamente anche le variabili con virgolette.