2010-08-11 9 views
15

In uno script di shell come trovo un file con un nome particolare e poi navigo in quella directory per fare ulteriori operazioni su di esso?Trova il file poi cd in quella directory in Linux

Da qui ho intenzione di copiare il file su un'altra directory (ma posso farlo già semplicemente aggiungendo in per il contesto.)

+0

trovare e individuare :) ma non posso individuare locatedb ritrovamento ?? – Candyfloss

+0

quindi leggi 'man 8 updatedb' – msw

+0

Ciao zucchero filato, per favore guarda questo, ho appena postato qualcosa che vorrei riassumere come soluzione estremamente conveniente a questo problema. Si prega di controllare la mia soluzione di cdf. :-) –

risposta

17

si può usare qualcosa di simile:

pax[/home/pax]> cd "$(dirname "$(find/-type f -name ls | head -1)")" 
pax[/usr/bin]> _ 

Questo localizzerà il primo file regolare ls quindi cambierà in quella directory.

In termini di ciò che ogni bit fa:

  • Il ritrovamento avrà inizio alle / e ricerca in giù, che elenca tutti i file regolari (-type f) chiamati ls (-name ls). Ci sono altre cose che puoi aggiungere a find per restringere ulteriormente i file che ottieni.
  • Le tubazioni attraverso head -1 filtreranno tutte tranne la prima.
  • $() è un modo per prendere l'output di un comando e metterlo sulla riga di comando per un altro comando.
  • dirname può richiedere una specifica di file completa e fornire il bit del percorso.
  • cd solo modifiche a quella directory.

Se si esegue ogni bit in sequenza, si può vedere cosa succede:

pax[/home/pax]> find/-type f -name ls 
/usr/bin/ls 

pax[/home/pax]> find/-type f -name ls | head -1 
/usr/bin/ls 

pax[/home/pax]> dirname "$(find/-type f -name ls | head -1)" 
/usr/bin 

pax[/home/pax]> cd "$(dirname "$(find/-type f -name ls | head -1)")" 

pax[/usr/bin]> _ 
+0

potresti spiegare cosa sta succedendo per favore? – Candyfloss

+0

@Ross: certo, eccolo. – paxdiablo

+1

Penso che sia necessario uno spazio tra '-type f' e' -name ls'. –

1

se si è solo trovare il file e poi si spostano altrove, basta usare trovare e -exec

find /path -type f -iname "mytext.txt" -exec mv "{}" /destination +; 
+1

Ho appena avuto una situazione simile in cui volevo rinominare copie di file con lo stesso nome in diverse directory. L'opzione '-execdir' di find ha fatto il trucco per me:' find. -name foo.txt -execdir mv "{}" bar.txt ";" "rinomina foo.txt in bar.txt in ogni directory in cui si trova. –

0

Se si tratta di un programma in PATH, si può fare:

o in Bash:

cd "$(dirname "$(type -P ls)")" 

che utilizza uno meno eseguibile esterno.

Questa non utilizza gli esterni:

dest=$(type -P ls); cd "${dest%/*}" 
+0

in cui la shell' cd' non richiede le virgolette? Dopo 'export d =" foo bar "; mkdir "$ d" ':' ksh -c 'cd $ d''complains' cd: sostituzione errata'; 'ash -c 'cd $ d'' si lamenta: 'can not cd to foo'; 'bash -c 'cd $ d'' si lamenta: 'cd: foo: Not a directory'. – Gilles

+0

@Gilles: avrei giurato che funzionasse in Bash. Modificherò la mia risposta. –

+0

non può funzionare in una shell conforme a POSIX, 'cd' non ha dispense speciali dalle solite regole di espansione. E ti mancano ancora le virgolette attorno all'argomento di 'dirname'. – Gilles

9

il seguente dovrebbe essere più sicura:

cd -- "$(find/-name ls -type f -printf '%h' -quit)" 

Vantaggi:

  • Il doppio trattino impedisce l'interpretazione di un nome di directory di partenza con un trattino come opzione (non produce tali nomi di file, ma non è dannoso e potrebbe essere richiesto per costrutti simili)
  • -name controllo prima -type controllo perché questi ultimi a volte richiede un stat
  • No dirname necessario perché l'identificatore %h stampa già il nome della directory
  • -quit per interrompere la ricerca dopo il primo file trovato , quindi non head necessario che causerebbe lo script per fallire su nomi delle directory contenenti ritorni a capo
+1

Per me, questa è la migliore risposta. Può essere persino abbreviato per la maggior parte dei casi e uno potrebbe seguire lo stile: 1) fai trovare il comando find per trovare quello che ti serve, ad es. '$ find. -nome *.xsd' 2) aggiungi il printf e -quit '$ find. -name * .xsd -printf "% h" -quit' 3) surround da backtics e feed in cd (e ommit - se non necessario): '$ cd \' find. -name * .xsd -printf "% h" -quit \ '' –

+0

la parte '-printf '% h'' fa in modo che questo comando non restituisca nulla, anche se ci sono file ... non del tutto sicuri del motivo – Blauhirn

1
function fReturnFilepathOfContainingDirectory { 
    #fReturnFilepathOfContainingDirectory_2012.0709.18:19 
    #$1=File 

    local vlFl 
    local vlGwkdvlFl 
    local vlItrtn 
    local vlPrdct 

    vlFl=$1 
    vlGwkdvlFl=`echo $vlFl | gawk -F/ '{ $NF="" ; print $0 }'` 
    for vlItrtn in `echo $vlGwkdvlFl` ;do 
     vlPrdct=`echo $vlPrdct'/'$vlItrtn` 
    done 
    echo $vlPrdct 

} 
1

Ampliando risposte già date, se si desidera navigare in modo iterativo per ogni file che find individua ed eseguire operazioni in ogni directory:

for i in $(find /path/to/search/root -name filename -type f) 
do (
    cd $(dirname $(realpath $i)); 
    your_commands; 
) 
done 
3

Sulla base di this answer a una domanda simile, altra scelta potrebbe essere utile avere 2 comandi, 1 ° per trovare il file e il 2 per navigare alla sua directory:

find ./ -name "champions.txt" 
cd "$(dirname "$(!!)")" 

Dove !! è storia di espansione significato 'il comando precedente'.

0

Semplicemente così, non è così elegante?

cdf yourfile.py 

Naturalmente è necessario configurarlo prima, ma è necessario fare questo solo una volta :

Aggiungete la seguente riga nel vostro .bashrc o .zshrc, qualunque cosa si usa come inizializzazione della shell script.

source ~/bin/cdf.sh 

E aggiungere questo codice nel file ~/bin/cdf.sh che è necessario creare da zero.

#!/bin/bash 

function cdf() { 
    THEFILE=$1 
    echo "cd into directory of ${THEFILE}" 
    # For Mac, replace find with mdfind to get it a lot faster. And it does not need args ". -name" part. 
    THEDIR=$(find . -name ${THEFILE} |head -1 |grep -Eo "/[ /._A-Za-z0-9\-]+/") 
    cd ${THEDIR} 
} 
0

Se il file è solo in una posizione che si potrebbe provare la seguente:

cd "$(find ~/ -name [filename] -exec dirname {} \;)" && ...

È possibile utilizzare -exec per richiamare dirname con il percorso che trovano i rendimenti (che va dove la {} segnaposto è). Questo cambierà le directory. È anche possibile aggiungere una doppia e commerciale (&&) per eseguire il comando successivo dopo che la shell ha cambiato la directory.

Ad esempio:
cd "$(find ~/ -name need_to_find_this.rb -exec dirname {} \;)" && ruby need_to_find_this.rb

Si cercherà quel file rubino, passare alla directory, quindi eseguirlo dall'interno di quella cartella. Questo esempio presuppone che il nome file sia univoco e che per qualche motivo lo script ruby ​​debba essere eseguito all'interno della sua directory. Se il nome del file non è univoco, avrai molte posizioni passate su cd, restituirà un errore quindi non cambierà le directory.

1

nessuno suggerisce la localizzazione (che è molto più veloce per alberi enormi)?

zsh:

cd $(locate zoo.txt|head -1)(:h) 
cd ${$(locate zoo.txt)[1]:h} 
cd ${$(locate -r "/zoo.txt$")[1]:h} 

or could be slow 

cd **/zoo.txt(:h) 

bash:

cd $(dirname $(locate -l1 -r "/zoo.txt$")) 
Problemi correlati