Quando la stringa vuota indica la directory corrente?


8

In uno script che uso findper raccogliere alcuni file nella directory corrente, come in

$ find . -name "*.h"
./foo.h

Ora mi piacerebbe che fosse appena prodotto foo.h, senza il ./prefisso. Ho pensato che la stringa vuota ""denotasse la directory corrente nei comandi di shell. Ma questo dà:

$ find "" -name "*.h"
find: ftsopen: No such file or directory

Quindi ho sbagliato. Ora la mia domanda è quando / come / dove / .. una "stringa vuota (?)" Indica la dir corrente nei comandi che prevedono un nome file o un percorso? C'è una spiegazione chiara e illuminante?

Una domanda a margine è se la ricerca del nitpicking sopra può essere risolta semplicemente, senza manipolazione di stringhe alla ${parameter#word}o cutoppure sed?


1
findha il parametro -printf per manipolare la modalità di visualizzazione dei risultati. find . -name '*.h' -printf '%P\n'rimuoverà il ./prefisso. Guarda cosa find . -name '*.h' -printfa.
Valentin Bajrami,

Grazie! Peccato che la mia versione di find non supporti l' -printfopzione. FWIW, stringssulla mia ricerca dà @(#)PROGRAM:find PROJECT:shell_cmds-175?!?
phs

5
@phs è il genere di cose che rende essenziale menzionare sempre il tuo sistema operativo.
terdon

Risposte:


11

Molto tempo fa (nella 7a edizione , 32V , 4.2BSD , 4.3BSD ), a livello di chiamata di sistema un percorso di lunghezza zero indicava la directory di lavoro corrente (quando usato per la ricerca; non era consentito quando si cercava di creare o eliminare un file o directory). In System III , è stato un errore utilizzare un percorso di lunghezza zero in tutte le circostanze, e lo standard POSIX ha questo da dire sulla risoluzione del percorso:

Un percorso null non deve essere risolto con successo.


3
Una stringa vuota in $ PATH, $ MANPATH, $ LD_LIBRARY_PATH (e altri, ma non necessariamente tutti $ * PATH) indica la directory corrente. dir/è per lo più lo stesso didir/.
Stéphane Chazelas,

4

Puoi usare:

find * -name "*.h"

Si noti che i file nella directory corrente il cui nome inizia con .saranno omessi, e i file il cui nome inizia con -saranno interpretati come opzioni finde causeranno il caos, quindi questo non è un equivalente generale di find . ….

L'assenza di una stringa che termina con " /" come parte del nome di un file implica la directory corrente, ma ciò non significa che la directory corrente sia indicata da una stringa vuota (che probabilmente non è la stessa dell'assenza di una stringa, anche se potrebbe apparire uguale quando stampato).


4

In generale, la stringa vuota non indica la directory corrente, né ai comandi di shell né nelle chiamate di sistema. Lo ha fatto su alcuni sistemi meno recenti, ma non su sistemi compatibili con POSIX .

Di tanto in tanto troverai un programma che utilizza la directory corrente quando passi una stringa vuota e il programma si aspetta un nome di directory. Questo a volte è intenzionale, e talvolta un effetto collaterale di anteporre il percorso assoluto della directory corrente quando la stringa data non inizia con una barra.

La cosa migliore per te sarebbe lasciare il ./. Non fa alcun male.

Se l'elenco dei file è per

find . … | sed 's!^\./!!'

Si noti che questo manipola alcuni nomi di file contenenti newline. Questo di solito non è un problema per il consumo umano e l'output di findnon è adatto al consumo del programma poiché è ambiguo. Se stai usando -print0, che è adatto per il consumo del programma, probabilmente non ti interessa ./comunque il prefisso.

Puoi usare find * …invece di find . …, ma nota che find *ha una serie di difetti che lo rendono inadatto in generale:

  • . è omesso.
  • Tutti i file punto (file il cui nome inizia con .o ..`) vengono omessi.
  • Se esiste un nome file nella directory corrente il cui nome inizia con -(o un file chiamato !o (...), verrà interpretato come un'opzione o predicato da find.

Il primo punto non importa se il filtro esclude la directory corrente. Per il secondo punto, puoi usare i pattern ..?* .[!.]* *per abbinare tutti i file nella directory corrente, ma dovrai controllare se ogni pattern corrisponde ad almeno un file e ometterlo se non lo fa. Questo è possibile ma molto ingombrante. L'ultimo punto è un tappo. Quindi find *può essere adatto per l'uso della riga di comando di Quickie, ma non utilizzarlo in uno script.

Un approccio alternativo consiste nell'utilizzare la funzione di globbing ricorsiva della shell, ad es

printf '%s\n' **/*.h

Questo deve essere attivato da shopt -s globstarin bash e da set -o globstarin ksh93 e non esiste in una shell POSIX di base come dash. I file di punti non verranno attraversati per impostazione predefinita; per includerli, prima fai in modo che il globbing non ignori i file punto con shopt -s dotglobin bash o FIGNORE='@(.|..)'in ksh93. Inoltre, se non ci sono corrispondenze, questo comando stampa il motivo; corri shopt -s nullglobin bash per stampare invece una riga vuota e usa il modello ~(N)**/*.hin ksh.

In zsh, il globbing ricorsivo è attivo per impostazione predefinita. Utilizzare il qualificatore glob Dper includere file dot e Nstampare una riga vuota se non ci sono corrispondenze (per impostazione predefinita, zsh genera un errore se un modello non corrisponde a nessun file). Puoi usare printfcome sopra o

print -rl -- **/*.h(DN)

Grazie per tutti questi suggerimenti. La maggior parte dei difetti find *sono nuovi per me e alcuni sono spaventosi !!
phs,

2

Non riesco a pensare a nessun esempio in cui la stringa vuota indica la directory corrente .. Potresti pensare a invocazioni come ls, ma questo perché lsassume la directory corrente se non viene fornito alcun parametro, e in effetti non prenderà la stringa vuota:

ulmi@silberfisch:~$ ls ""
ls: cannot access : No such file or directory

3
Un esempio in cui la stringa vuota indica la directory corrente è come PATHcomponente.
hvd,

0

Esistono vari trucchi che è possibile utilizzare per ottenere l'output di ricerca senza il comando iniziale ./:

  1. Usa l' -printfopzione find e digli di stampare solo %f. Vedi man find:

    % f Nome del file con eventuali directory principali rimosse (solo l'ultimo elemento).

    Per esempio:

    find . -name "*.h" -printf "%f\n"
    
  2. Analizza l'output:

    find . -name "*.h" | sed 's#^./##'
    
  3. @ Il trucco di Anthon

    find * -name "*.h"
    

Per quanto riguarda l'altra domanda, la stringa vuota non indica mai la directory corrente. È solo che vari programmi prendono la directory corrente come predefinita, quindi quando li esegui senza argomenti, vengono eseguiti sulla directory corrente.


Ciò presuppone GNU find. Oppure usa %Psolo per spogliare il./
Stéphane Chazelas il

1
find * -name '*.h'troverà foo/.bar.h, ma non .bar.hnella directory corrente.
Stéphane Chazelas,

0

Se i file si trovano nella directory corrente puoi semplicemente usare ls:

$ ls *.sh

Se vuoi anche i file nelle sottodirectory e hai solo bisogno del nome del file, potresti fare qualcosa del tipo:

$ find . -name '*.h' -exec basename {} \;

Ci sono comandi che otterranno l'assenza di una stringa come directory corrente, ma fondamentalmente perché otterranno la directory corrente come predefinita se non è stato inserito nulla. La .indicare sempre la directory corrente (e ..la directory padre)


l'OP voleva solo ./ rimosso, mentre la findsoluzione rimuove tutti i componenti della directory
artm
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.