GNU trova e maschera il {} per alcune shell - quale?


34

La pagina man per GNU find afferma:

-exec command ;
    [...] The  string `{}'  is  replaced  by the current 
    file name being processed everywhere it occurs in the 
    arguments to the command, not just in arguments where 
    it is alone, as in some  versions  of  find.
    Both  of  these  constructions might need to be escaped 
    (with a `\') or quoted to protect them from expansion 
    by the shell. 

Questo è dall'uomo a find(GNU findutils) 4.4.2.

Ora ho provato questo con bash e dash, ed entrambi non hanno bisogno di {}essere mascherati. Ecco un semplice test:

find /etc -name "hosts" -exec md5sum {} \; 

Esiste un guscio, per il quale ho davvero bisogno di mascherare le parentesi graffe? Nota che non dipende dal fatto che il file trovato contenga uno spazio vuoto (invocato da bash):

find ~ -maxdepth 1 -type d -name "U*" -exec ls -d {} \; 
/home/stefan/Ubuntu One

Questo cambia se il file trovato viene passato a una subshell:

find ~ -maxdepth 3 -type d -name "U*" -exec bash -c 'ls -d {}' \; 
ls: cannot access /home/stefan/Ubuntu: No such file or directory
ls: cannot access One: No such file or directory

che può essere risolto da:

find ~ -maxdepth 3 -type d -name "U*" -exec bash -c 'ls -d "$0"' {} \;

in contrasto con:

find ~ -maxdepth 3 -type d -name "U*" -exec bash -c 'ls -d "{}"' \; 
/home/stefan/Ubuntu One

ma non è di questo che parla la pagina man, vero? Quindi quale shell tratta {}in modo diverso?


@Volker Siegel: la tua modifica potrebbe essere avvenuta in buone intenzioni, ma ho controllato il mio attuale manuale di ricerca e le tue correzioni sono sbagliate, hai anche perso l'opportunità di riassumere le tue modifiche che è una cattiva abitudine, quindi rinnovo le tue modifiche. Scusa amico.
utente sconosciuto

Oh, grazie per averlo riavviato se si fosse rotto qualcosa. Stavo ricordando che il compilatore di testo che genera il formato della pagina man utilizzato per generare queste "virgolette tipografiche" come artefatto della definizione di rendering. Può anche eseguire il rendering su TeX per una formattazione perfetta della stampa. Ho notato le virgolette perché hanno confuso l'evidenziazione della sintassi. Ho supposto che l'insolita prima citazione sia sbagliata quando usata nel codice, e suppongo ancora che. Si noti che le due modifiche erano nel testo descrittivo, non nel codice. Quindi se li vediamo come tipografia - rendering estetico - hanno ragione.
Volker Siegel,

Sembra che nel rendering dell'output delle informazioni, la stessa citazione sia usata su entrambi i lati. Non c'è dubbio che il mio cambiamento lo abbia reso diverso dall'originale, hai ragione. Ma ha causato qualche problema? (Considero la prima citazione come un bug nella definizione di rendering dell'uomo, è l'unico caso di tipografia per quanto ne so.)
Volker Siegel

Ho appena controllato: `{} 'non funziona sulla riga di comando. È tecnicamente corretto, ma non mi piace che un utente ignaro riceva uno strano errore quando tenta di copiarlo e incollarlo.
Volker Siegel,

@VolkerSiegel: è un testo in prosa, non un codice, quindi cosa deve copiare e incollare un utente qui? Ed è una citazione della pagina man del 2011. Non vedo alcun valore correggere il passaggio per poi sottolineare, perché ho apportato correzioni alla pagina man. L'argomento è abbastanza complicato. Se questa fosse la tua domanda, non proverei a convincerti, a citare accuratamente la pagina man ma, per la mia domanda, non ho voglia di scendere a compromessi. La citazione è citazione.
utente sconosciuto

Risposte:


26

Riepilogo : se c'è mai stata una shell che si è espansa {}, è ormai roba legacy davvero vecchia.

Nella shell Bourne e conchiglie POSIX-compliant, bretelle ( {e }) sono caratteri ordinari (differenza (e )che sono delimitatori di parola come ;e &, e [e ]che sono globbing caratteri). Le seguenti stringhe dovrebbero essere stampate letteralmente:

$ echo { } {} {foo,bar} {1..3}
{ } {} {foo,bar} {1..3}

Una parola composta da una singola parentesi graffa è una parola riservata , che è speciale solo se è la prima parola di un comando.

Ksh implementa l'espansione del controvento come estensione incompatibile della shell Bourne. Questo può essere disattivato con set +B. Bash emula ksh in questo senso. Zsh implementa anche l'espansione del controvento; lì può essere spento con set +Io setopt ignore_braceso emulate sh. Nessuna di queste shell si espande {}in ogni caso, anche quando si tratta di una sottostringa di una parola (ad esempio foo{}bar), a causa dell'uso comune negli argomenti di finde xargs.

Unico Unix v2 lo nota

In alcuni sistemi storici, le parentesi graffe sono trattate come operatori di controllo. Per aiutare nelle future attività di standardizzazione, le applicazioni portatili dovrebbero evitare di usare parentesi graffe non quotate per rappresentare i personaggi stessi. È possibile che una futura versione della norma ISO / IEC 9945-2: 1993 possa richiederlo {ed }essere trattata individualmente come operatori di controllo, sebbene il token {}sarà probabilmente un'esenzione da questo caso speciale a causa del find {}costrutto spesso usato .

Questa nota è stata eliminata nelle versioni successive dello standard; gli esempi perfind hanno usi non quotati di {}, così come gli esempi perxargs . Potrebbero esserci stati gusci di Bourne storici nei quali {}dovevano essere citati, ma ormai sarebbero stati sistemi legacy molto vecchi.

Le implementazioni CSH che ho a portata di mano (OpenBSD 4.7, BSD csh su Debian , tcsh) tutto si espandono {foo}a fooma lasciare {}da solo.


1
@geekosaur: solo un piccolo sottoinsieme di markdown funziona nei commenti . Non so cosa stai cercando di dire. Se si tratta dell'espansione di parentesi graffe di ksh et al, leggi il mio paragrafo che inizia con "Ksh implementa l'espansione di parentesi graffe come estensione incompatibile".
Gilles 'SO- smetti di essere malvagio' il

2
Quello era bash(vedi $BASH_VERSION). L'espansione del tutore è molto viva e vegeta.
Geekosaur,

2
Questo era il punto. La {}sintassi è nata in csh, ma {}espansa nella stringa vuota. Le conchiglie più recenti riconoscono che non ha senso, ma ci sono ancora alcuni vecchi csh.
Geekosaur,

1
@geekosaur: puoi dire quale specifica versione di csh su quale piattaforma specifica? Preferirei testarlo da solo (se è possibile su Linux) o essere sicuro che la persona lo testi da solo.
utente sconosciuto

1
@geekosaur, {}foosi espanderebbe a foo, ma {}si espanderebbe a {}(tranne quando all'interno di backtick, ma la citazione non sarebbe d'aiuto) ed è stata documentata come tale. L'ho verificato per il csh di 2BSD (prima versione), 2.79BSD, 2.8BSD e 2.11BSD.
Stéphane Chazelas,

12

È {}necessario che sia citato nelle versioni della fishshell precedenti alla 3.0.0.

$ fish -c 'echo find -exec {} \;'
find -exec  ;

E nella shell rc (anche akangabasata su rc, ma non es):

$ rc -c "echo find -exec {} ';'"
line 1: syntax error near '{'

Probabilmente non sono queste le shell che gli autori di quella GNU hanno scoperto nella documentazione quando hanno scritto quel testo da quando è fishstato rilasciato per la prima volta nel 2005 (mentre quel testo o simile era già lì nel 1994) e rcnon era originariamente una shell Unix.

Ci sono alcune voci su alcune versioni di csh(la shell che ha introdotto l'espansione del supporto) che lo richiedono. Ma è difficile dare credito a quelli dal momento che la prima versione di csh2BSD non lo ha fatto. Ecco come testato in un emulatore PDP11:

# echo find -exec {} \;
find -exec {} ;

E la pagina man di 2BSD cshafferma chiaramente :

Come caso speciale `{',`}' e `{} 'vengono passati indisturbati.

Quindi troverei molto strano se una versione successiva di csh o tcsh in seguito lo avesse rotto.

Potrebbe essere stato per aggirare alcuni bug in alcune versioni. Sempre con quel 2BSD csh (è lo stesso in 2.79BSD, 2.8BSD, 2.11BSD):

# csh -x
# echo foo {} bar
echo foo {} bar
foo {} bar
# echo `echo foo {} bar`
echo `echo foo {} bar`
echo foo {} bar
foo  bar

La citazione non aiuta però:

# echo `echo foo '{}' bar`
echo `echo foo '{}' bar`
echo foo {} bar
foo  bar

Potresti citare l'intera sostituzione del comando:

# echo "`echo foo {} bar`"
echo `echo foo {} bar`
echo foo {} bar
foo {} bar

Ma questo sta trasmettendo un argomento a quell'eco esterna.

In csho tcsh, dovresti citare il {}quando non da solo come in:

find . -name '*.txt' -type f -exec cp {} '{}.back' \;

(anche se quel tipo di findutilizzo non è portatile in quanto alcuni findsi espandono solo {}da soli).


1

In una parola, csh. bashe altre shell moderne riconoscono che l'utente probabilmente non sta chiedendo un'espansione di parentesi graffa nulla. (Il moderno cshè in realtà tcshe potrebbe anche gestire in modo {}sano ormai.)


Bello sentire, ma sto chiedendo il contrario, un guscio per il quale non lo gestisce in modo sano.
utente sconosciuto

Stai supponendo che qualcuno entrerebbe e strappasse il riferimento della pagina di informazioni alle quotazioni extra solo perché i sistemi Linux hanno tutti più recenti csh. Non tutti eseguono utility GNU su Linux; infatti è abbastanza comune installarli su vecchi sistemi commerciali Unix i cui comandi in bundle sono limitati. (La sostituzione cshsu tali sistemi è meno probabile, poiché gli script di sistema possono fare affidamento sulle idiosincrasie dell'originale cshe anche se gli utenti fossero tutti configurati per utilizzare un nuovo csh, rootquasi sicuramente dovrebbe rimanere la versione in bundle.)
geekosaur

2
No. Sono in discussione con un ragazzo che dice che nel nostro wiki dovremmo dare il consiglio di usare sempre "{}", perché lo dice la pagina man. E ora vorrei sapere se c'è una shell che non sto usando, come ksh, zsh, tcsh, csh o XYZsh che non conosco, per cui questa affermazione è vera, o se posso onestamente supporre che non c'è. Se ci sono shell per diversi Unix che hanno bisogno di "{}", questa sarebbe una buona spiegazione del motivo per cui la frase è ancora nella pagina man, ma non appropriata come consiglio per i principianti di Linux.
utente sconosciuto

Ora mi chiedo se pdkshfa la cosa giusta ... anche se la risposta corretta a che è probabilmente "reale kshè FOSS in questi giorni".
Geekosaur,

4
Pdksh, come mksh, ksh93, bash e zsh, espande le parentesi graffe solo quando c'è una virgola tra (o ..per ksh93, bash e zsh). Solo espande (t) CSH {foo}a foo, e persino lascia {}da solo (almeno sulla recente BSD di).
Gilles 'SO- smetti di essere malvagio' il
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.