Comportamento imprevisto con echo [[: digit:]]


Risposte:


34

Perché sono due cose diverse. Questo {1,2,3}è un esempio di espansione di parentesi graffe . Il {1,2,3}costrutto viene espanso dalla shell , prima echoancora di vederlo. Puoi vedere cosa succede se usi set -x:

$ set -x
$ echo {1,2,3}
+ echo 1 2 3
1 2 3

Come puoi vedere, il comando echo {1,2,3}è espanso in:

echo 1 2 3

Tuttavia, [[:digit:]]è una classe di caratteri POSIX . Quando lo dai echo, la shell lo elabora anche per primo, ma questa volta viene elaborato come un glob shell . funziona allo stesso modo come se si esegue, echo *che stamperà tutti i file nella directory corrente. Ma [[:digit:]]è un glob shell che corrisponderà a qualsiasi cifra. Ora, in bash, se un glob di shell non corrisponde a nulla, verrà espanso su se stesso:

$ echo /this*matches*no*files
+ echo '/this*matches*no*files'
/this*matches*no*files

Se il glob corrisponde a qualcosa, verrà stampato:

$ echo /e*c
+ echo /etc
/etc

In entrambi i casi, echostampa qualunque cosa la shell gli dica di stampare, ma nel secondo caso, poiché il glob corrisponde a qualcosa ( /etc) viene detto di stampare quel qualcosa.

Quindi, dal momento che non hai file o directory il cui nome è costituito esattamente da una cifra (che è ciò [[:digit:]]che corrisponderebbe), il glob viene espanso su se stesso e ottieni:

$ echo [[:digit:]]
[[:digit:]]

Ora prova a creare un file chiamato 5ed eseguendo lo stesso comando:

$ echo [[:digit:]]
5

E se ci sono più file corrispondenti:

$ touch 1 5       
$ echo [[:digit:]]
1 5

Questo è (in qualche modo) documentato nella man bashspiegazione delle nullglobopzioni che disattivano questo comportamento:

nullglob
    If  set,  bash allows patterns which match no files (see
    Pathname Expansion above) to expand to  a  null  string,
    rather than themselves.

Se imposti questa opzione:

$ rm 1 5
$ shopt -s nullglob
$ echo [[:digit:]]  ## prints nothing

$ 

4
Vedi anche shopt -s failglobper ottenere un comportamento più utile simile a quello delle conchiglie moderne come zsho fish.
Stéphane Chazelas,

Sono d'accordo con Stéphane, usa failglob. nullglobpuò causare problemi imprevisti, ad esempio quando si incolla un URL che sembra avere un ?.
Kevin

1
Certo, ho solo menzionato nullglobper dimostrare che il modello viene interpretato come un glob dalla shell.
terdon

14

{1,2,3}è espansione di parentesi graffe , si espande alle parole elencate senza riguardo al loro significato.

[...]è un gruppo di caratteri, utilizzato nell'espansione del nome file (o jolly o glob) in modo simile all'asterisco *e al punto interrogativo ?. Corrisponde a qualsiasi singolo carattere elencato all'interno o ai caratteri membri dei gruppi denominati, ad esempio [:digit:]se sono elencati. Il comportamento predefinito della maggior parte delle shell è di lasciare il carattere jolly così com'è se non ci sono file corrispondenti.

(Nota che non puoi davvero trasformare un carattere jolly / modello nell'insieme di stringhe che corrisponderebbe. L'asterisco può corrispondere a qualsiasi stringa di qualsiasi lunghezza, quindi espandere qualsiasi modello che lo contiene produrrebbe un elenco infinito di stringhe.)

Così:

$ bash -c 'echo [[:digit:]]'           # bash leaves it as-is
[[:digit:]]
$ zsh -c 'echo [[:digit:]]'            # zsh by default complains if no match
zsh:1: no matches found: [[:digit:]]
$ touch 1 3 d i g t
$ bash -c 'echo [[:digit:]]'           # now there are two matches
1 3                                    # note that d, i, g and t do NOT match

Ma ancora:

$ bash -c 'echo {1,2,3}'
1 2 3

Entrambi sono espansi dalla shell , non importa se il comando che stai eseguendo è ls, o echoo rm. Inoltre, se uno di questi è citato, non verranno espansi:

$ bash -c 'echo "[[:digit:]]"'         # even though matching files still exist
[[:digit:]]
$ bash -c 'echo "{1,2,3}"'
{1,2,3}

grazie per la tua risposta, sono nuovo di Linux, quindi lascia che ti chieda in che modo l'eco è correlato ai file 1 3, la sua funzione è quella di stampare i suoi argomenti su stdout non cercando file per quanto ne
so

1
@AbdAllahTalaat questo non ha nulla a che fare con l'eco, in realtà. La shell (es. Bash) "espanderà" il [[:digit:]] prima di passarlo echo, quindi echonon vede mai [[:digit:]], vede solo 1 3. Puoi vederlo in azione eseguendo set -xche stamperà i comandi effettivi in ​​esecuzione (esegui set +xper spegnerlo di nuovo).
terdon

@AbdAllahTalaat, echonon cerca i file, lo fa la shell , prima di eseguire il file echo.
Ilkkachu,

Soprattutto da quando penso che in DOS / Windows le utility espandano i caratteri jolly, non la shell. (Forse sbaglio)
ilkkachu

scusate ragazzi ho spostato la risposta corretta alla risposta di tedron perché il suo commento conteneva il significato che bash è ciò che il lavoro non fa eco ... la sua risposta conteneva anche quel significato .. tutti voi mi avete aiutato ... avrei voluto se potessi mettere risposta corretta per tutte le vostre risposte e commenti
AbdAllah Talaat

4

{1,2,3}(e ad esempio {1..3}sono espansioni di parentesi graffe . Vengono interpretate dalla shell prima dell'esecuzione del comando.

[[:digit:]]è un token corrispondente al modello , ma non lo si utilizza in una posizione con alcun file corrispondente a quel modello. Se si utilizza una corrispondenza del modello che non ha corrispondenze, si espande da sola:

$ echo [[:digit:]]; touch 3; echo [[:digit:]]
[[:digit:]]
3

No, come indicano correttamente le altre risposte, il modello è abbinato ai nomi dei file.
Toby Speight,
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.