confuso sulle variabili in bash


0

So che le variabili in bash non hanno tipo, ma sono confuso riguardo al valore a cui sono assegnate.

Il seguente semplice script funziona bene in bash

#!/bin/bash 
tail -n +2 /cygdrive/c/workdir\ \(newco\,\ LLC\)/workfile.txt > \
/cygdrive/c/workdir\ \(newco\,\ LLC\)/workfile2.txt

Tuttavia, il seguente non lo fa

#!/bin/bash
tmpdir=/cygdrive/c/workdir\ \(newco\,\ LLC\)
tail -n +2 $tmpdir/workfile.txt > $tmpdir/workfile2.txt

C'è una spiegazione per questo comportamento?

Risposte:


3

Dovresti assicurarti di citare le variabili che potrebbero contenere degli spazi. Nel tuo caso, tail sta ricevendo tre file: /cygdrive/c/workdir, (newco, e LLC) perché $tmpdir ha tre parole separate da spazi.

So che sei sfuggito allo spazio quando lo hai assegnato $tmpdir, ma ciò serviva semplicemente a evitare che ogni parola venisse interpretata come un comando separato durante l'assegnazione. Se tu allora echo $tmpdir, otterrete
/cygdrive/c/workdir (newco, LLC), e quello è cosa è passato a tail.

Per evitare questo, citare $tmpdir:

tail -n +2 "${tmpdir}/workfile.txt" > "${tmpdir}/workfile2.txt"

Grazie. Qual è la differenza tra "$ {tmpdir} /workfile.txt" e "$ tmpdir / workfile.txt"?
gappy

2
Le parentesi graffe vengono utilizzate per garantire un'analisi corretta dei nomi delle variabili. Se hai avuto una variabile chiamata tmp potresti fare qualcosa di simile ${tmp}dir/workfile.txt sostituirlo invece di intero $tmpdir (ammesso che esista anche uno).
gronostaj

0

Digita la prima riga in bash e poi echo quella variabile, questo è ciò che vedrai:

$ tmpdir=/cygdrive/c/workdir\ \(newco\,\ LLC\)
$ echo $tmpdir
/cygdrive/c/workdir (newco, LLC)

Se non è ancora chiaro quale sia il colpevole, aggiungi echo all'inizio della seconda riga e avvolgila tra virgolette. Vedrai quale comando viene effettivamente eseguito:

$ echo "tail -n +2 $tmpdir/workfile.txt > $tmpdir/workfile2.txt"
tail -n +2 /cygdrive/c/workdir (newco, LLC)/workfile.txt > /cygdrive/c/workdir (newco, LLC)/workfile2.txt

Hai assegnato correttamente l'assegnazione della variabile, ma non è abbastanza. Bash esegue una semplice sostituzione della sottostringa, inserendo quindi spazi aggiuntivi e interrompendo il comando.

Come suggerito da @savanto nella sua risposta, è possibile racchiudere le variabili tra virgolette per garantire che gli spazi aggiuntivi non vengano trattati come separatori di argomenti. Questa linea:

tail -n +2 "${tmpdir}/workfile.txt" > "${tmpdir}/workfile2.txt"

sarà simile a questo dopo la sostituzione della variabile:

tail -n +2 "/cygdrive/c/workdir (newco, LLC)/workfile.txt" > "/cygdrive/c/workdir (newco, LLC)/workfile2.txt"

Questo è il modo più comune e preferito per risolvere questo problema. Se vuoi disperatamente evitare le virgolette doppie, puoi provare a eseguire il doppio escape: prima durante l'assegnazione, poi dopo la sostituzione.

$ tmpdir=/cygdrive/c/workdir\\\ \\\(newco\\\,\\\ LLC\\\)
$ echo $tmpdir
/cygdrive/c/workdir\ \(newco\,\ LLC\)

Spiegazione rapida delle triple backslash: un backslash significa: "considera il prossimo carattere come un personaggio normale, ignora qualsiasi significato speciale" (ad es. sfuggirlo ). Il primo backslash è un carattere di escape, quindi il secondo sarà trattato come un carattere backslash, non come un carattere di escape. Pertanto, il doppio backslash produce un singolo backslash. Il terzo sfugge semplicemente al carattere successivo, come spazio o parentesi. Per esempio a\\\ b diventerà a\ b.

Ora, se sostituiamo le variabili nel tuo comando, sarà evaso correttamente:

tail -n +2 /cygdrive/c/workdir\ \(newco\,\ LLC\)/workfile.txt > /cygdrive/c/workdir\ \(newco\,\ LLC\)/workfile2.txt
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.