03: Scalari, quoting e blocchi multiriga
← 02 - Struttura - documenti, mapping, indentazione · Indice · successivo → 04 - Tipi, risoluzione implicita e trappole
Questo è il modulo che elimina più bug per riga letta.
3.1 Tre modi di scrivere una stringa
Plain (senza virgolette): il default:
messaggio: ciao mondoNessun escaping possibile. Non può iniziare con la maggior parte dei caratteri speciali, e
soprattutto non può contenere : (due punti + spazio) né # (spazio + cancelletto).
Apici singoli: stringa quasi letterale:
percorso: 'C:\Users\ale\file.txt'
apostrofo: 'l''idea'L’unico escaping possibile è raddoppiare l’apice. Il backslash non ha alcun significato:
'a\nb' è letteralmente a\nb, backslash compreso. È per questo che gli apici singoli sono
la scelta giusta per percorsi Windows, regex e template.
Apici doppi: l’unica forma con escape veri:
testo: "prima riga\nseconda riga\ttabulata"
unicode: "\u00e8 anche \U0001F600"Escape ammessi: \n \t \r \0 \\ \" \/ \b \f \v \e \xNN \uNNNN \UNNNNNNNN e altri. Una
lettera non prevista dopo il backslash è un errore, non un backslash letterale.
Quale usare
- Plain quando il valore è chiaramente testo e non contiene caratteri speciali.
- Apici singoli ogni volta che devi proteggere un valore: è la scelta di default per il quoting difensivo.
- Apici doppi solo quando ti servono davvero
\n,\to caratteri Unicode espliciti.
3.2 Quando le virgolette sono obbligatorie
Regola pratica: guarda il primo carattere e i caratteri speciali.
Servono le virgolette se il valore:
| Caso | Esempio che rompe | Corretto |
|---|---|---|
| è un valore ambiguo (vedi 04 - Tipi, risoluzione implicita e trappole) | paese: NO | paese: 'NO' |
contiene : | titolo: Casa: dolce casa | titolo: 'Casa: dolce casa' |
contiene # | colore: #FF0000 | colore: '#FF0000' |
inizia con * | pwd: *segreto | pwd: '*segreto' |
inizia con & | pwd: &chiave | pwd: '&chiave' |
inizia con ! | if: !cancelled() | if: '!cancelled()' |
inizia con %, @, ` | ps: %PS-Adobe | ps: '%PS-Adobe' |
inizia con { o [ | tpl: {{ x }} | tpl: '{{ x }}' |
inizia con - seguito da spazio | nota: - primo | nota: '- primo' |
| ha spazi iniziali o finali che contano | t: valore | t: 'valore ' |
✅ verificato, i tre casi più insidiosi:
a: &x→{'a': None}. Nessun errore:&xviene letto come un’ancora su un valore vuoto. Una password che inizia con&sparisce in silenzio.color: #FF0000→{'color': None}.title: Home: dolce casa→ScannerError: mapping values are not allowed here.
Il primo è il peggiore: gli altri due almeno danno un errore o un valore vuoto evidente.
3.3 Blocchi multiriga: | e >
Due caratteri, due semantiche opposte.
| (literal): gli a capo si conservano:
script: |
echo "primo comando"
echo "secondo comando"✅ verificato → 'echo "primo comando"\necho "secondo comando"\n'
> (folded): gli a capo diventano spazi:
descrizione: >
Questo testo lungo
viene unito in una riga sola.✅ verificato → 'Questo testo lungo viene unito in una riga sola.\n'
La regola più importante di questo modulo
Negli script usa sempre
|. Con>,echo unoseguito daecho duediventaecho uno echo due: la shell riceve una riga sola e il comando fa una cosa diversa da quella che hai scritto. È un errore classico nei workflow CI.
Dentro un blocco non esiste escaping: #, :, {{ }}, apici: tutto è testo puro.
È anche il motivo per cui i blocchi sono il posto giusto per script, template e testi lunghi.
3.4 Chomping: cosa succede all’ultimo a capo
Il modificatore - o + dopo | o > decide che fine fanno gli a capo finali.
✅ tabella verificata eseguendo PyYAML:
| Forma | A capo interni | A capo finale | Righe vuote finali |
|---|---|---|---|
| | conservati | uno | eliminate |
|- | conservati | nessuno | eliminate |
|+ | conservati | conservato | conservate tutte |
> | diventano spazi | uno | eliminate |
>- | diventano spazi | nessuno | eliminate |
>+ | diventano spazi | conservato | conservate |
Quale usare:
|(clip) per gli script: il newline finale è quello che si aspetta la shell.|-(strip) quando la stringa finisce dentro un file, una variabile o un messaggio e non vuoi una riga vuota di troppo. È il default sensato per ivalue_template.|+(keep) quasi mai.
Il chomping è invisibile nel diff: è la causa numero uno del “il file generato ha una riga vuota in più e non capisco perché”.
3.5 Il dettaglio di > che nessuno conosce
Il folding non si applica alle righe più indentate. ✅ verificato:
testo: >
riga1
riga2
para2
più indentata
fine→ 'riga1 riga2\npara2\n più indentata\nfine\n'
Cioè: le righe normali vengono unite, una riga vuota produce un a capo, e una riga con
indentazione extra mantiene il suo a capo e i suoi spazi. Se dentro un > “abbellisci”
un comando lungo indentandolo, ne cambi il valore.
3.6 Indentation indicator
Se la prima riga del blocco è volutamente indentata più delle altre, YAML si confonde (prende quell’indentazione come base e la toglie a tutte). Si risolve dichiarando esplicitamente il livello:
codice: |2
questa riga ha due spazi in più
baseRaro, ma quando serve non c’è alternativa. Nota: la cifra va da 1 a 9, mai 0.
3.7 Un caso reale: template e espressioni
Il quoting non dipende dal motore di template, ma da come inizia il valore:
# Home Assistant / Jinja2: inizia con {{ → YAML lo legge come flow mapping → ERRORE
value_template: {{ states('sensor.temperatura') }} # ✗ rotto
value_template: "{{ states('sensor.temperatura') }}" # ✓✅ verificato: la prima forma dà while constructing a mapping ... found unhashable key.
# GitHub Actions: inizia con $ → nessun problema, le virgolette non servono
run: echo ${{ github.sha }} # ✓
if: ${{ !cancelled() }} # ✓
if: '!cancelled()' # ✓ (le virgolette qui SERVONO: inizia con !)Regola generale: se il template contiene apici, usa l’altro tipo di apice per il valore;
se ne contiene di entrambi i tipi, passa a un blocco |.
Esercizi
- Scrivi lo stesso script di due comandi prima con
|e poi con>. Leggi il valore risultante in Python e osserva la differenza. - Metti alla prova il chomping: crea
|,|-e|+con lo stesso contenuto e stamparepr()dei tre valori. - Prendi cinque valori di un tuo file reale e chiediti, per ciascuno, se sopravvivrebbe senza virgolette in entrambe le versioni di YAML.
- Scrivi un
value_templateJinja2 che contiene sia apici singoli sia doppi. Fallo funzionare.