Qual è la differenza tra grep apple file
e grep "apple" file
? Cosa fanno le virgolette? Entrambi sembrano funzionare e fare esattamente la stessa cosa (visualizzare la stessa linea).
Qual è la differenza tra grep apple file
e grep "apple" file
? Cosa fanno le virgolette? Entrambi sembrano funzionare e fare esattamente la stessa cosa (visualizzare la stessa linea).
Risposte:
Le virgolette hanno un effetto su quali caratteri la tua shell considera speciali e hanno un significato sintattico. Nel tuo esempio questo non fa differenza perché apple
non contiene tali caratteri.
Ma considera un altro esempio: grep apple tree file
cercherà la parola apple
nei file tree
e file
, mentre grep "apple tree" file
cercherà la parola apple tree
nel file file
. Le virgolette indicano a bash che lo spazio delle parole in "apple tree"
non avvia un nuovo parametro ma deve far parte del parametro corrente. grep apple\ tree file
produrrebbe lo stesso risultato, perché \
dice a bash di ignorare il significato speciale del personaggio seguente e trattarlo letteralmente.
"
) e virgolette singole ( '
). Le virgolette singole impediscono l'interpretazione di alcuni caratteri come $
, mentre le virgolette doppie consentono l'interpretazione. Ad esempio grep '${USER}'
cercherà il testo ${USER}
, mentre grep "${USER}"
cercherà il testo che USER
contiene la variabile (ad esempio johnstacen
).
Le virgolette doppie consentono la valutazione, le virgolette singole impediscono la valutazione, nessuna virgola consente l'espansione di caratteri jolly, se utilizzata sulla riga di comando. Come esempi inventati:
[user@work test]$ ls .
A.txt B.txt C.txt D.cpp
# The following is the same as writing echo 'A.txt B.txt C.txt D.cpp'
[user@work test]$ echo *
A.txt B.txt C.txt D.cpp
[user@work test]$ echo "*"
*
[user@work test]$ echo '*'
*
# The following is the same as writing echo 'A.txt B.txt C.txt'
[user@work test]$ echo *.txt
A.txt B.txt C.txt
[user@work test]$ echo "*.txt"
*.txt
[user@work test]$ echo '*.txt'
*.txt
[user@work test]$ myname=is Fred; echo $myname
bash: Fred: command not found
[user@work test]$ myname=is\ Fred; echo $myname
is Fred
[user@work test]$ myname="is Fred"; echo $myname
is Fred
[user@work test]$ myname='is Fred'; echo $myname
is Fred
Comprendere il modo in cui funzionano le citazioni è fondamentale per comprendere Bash. Per esempio:
# for will operate on each file name separately (like an array), looping 3 times.
[user@work test]$ for f in $(echo *txt); do echo "$f"; done;
A.txt
B.txt
C.txt
# for will see only the string, 'A.txt B.txt C.txt' and loop just once.
[user@work test]$ for f in "$(echo *txt)"; do echo "$f"; done;
A.txt B.txt C.txt
# this just returns the string - it can't be evaluated in single quotes.
[user@work test]$ for f in '$(echo *txt)'; do echo "$f"; done;
$(echo *txt)
È possibile utilizzare virgolette singole per passare un comando tramite una variabile. Le virgolette singole impediranno la valutazione. Le virgolette doppie verranno valutate.
# This returns three distinct elements, like an array.
[user@work test]$ echo='echo *.txt'; echo $($echo)
A.txt B.txt C.txt
# This returns what looks like three elements, but it is actually a single string.
[user@work test]$ echo='echo *.txt'; echo "$($echo)"
A.txt B.txt C.txt
# This cannot be evaluated, so it returns whatever is between quotes, literally.
[user@work test]$ echo='echo *.txt'; echo '$($echo)'
$($echo)
Puoi usare virgolette singole tra virgolette doppie e puoi usare virgolette doppie tra virgolette doppie, ma le virgolette doppie tra virgolette singole non devono essere eseguite (senza evitarle) non verranno valutate, verranno interpretate letteralmente. Le virgolette singole all'interno di virgolette singole non devono essere eseguite (senza sfuggirle).
Per utilizzare efficacemente Bash devi acquisire una conoscenza approfondita delle citazioni. Molto importante!
Come regola generale, non uso le virgolette se voglio che Bash espanda qualcosa in elementi (come un array), uso virgolette singole per stringhe letterali che non devono essere modificate e faccio un uso liberale di virgolette doppie per le variabili che probabilmente restituiranno qualsiasi tipo di stringa. Questo per garantire che vengano preservati spazi e caratteri speciali.
grep a*b equations.txt
allora cercheràa*b
, a meno che non ci sia un file nella directory corrente che inizia con ae termina con b, nel qual caso (perché (ba) sh espanderà i nomi dei file sulla riga di comando) grep verrà chiamato con completare parametri diversi, con risultati diversi. Questo di solito è più un problema con find, poiché un comando similefind . -name *.txt
comporterà un comportamento imprevisto, se esiste un file txt nella directory corrente. In questo caso è meglio usare le virgolette.