Perché non riesco a reindirizzare l'output di un nome percorso da un comando a "cd"?


27

Sto cercando di cdaccettare un nome di directory reindirizzato ad esso da un altro comando. Nessuno di questi metodi funziona:

$ echo $HOME | cd
$ echo $HOME | xargs cd

Questo funziona:

$ cd $(echo $HOME)

Perché il primo set di comandi non funziona e ce ne sono altri che falliscono in questo modo?


Da altri ti riferisci ad altri comandi o altri metodi per usare cd che falliscono in questo modo?
Didi Kohen,

@DavidKohen Mi riferisco ad altri comandi
Jhonathan,

Alcuni esempi notevoli sono ulimit, umask, popd, pushd, set, export e read.
Didi Kohen,

Risposte:


32

cdnon è un comando esterno - è una funzione integrata nella shell. Funziona nel contesto della shell corrente e non, come fanno i comandi esterni, in un contesto fork / exec'd come processo separato.

Il tuo terzo esempio funziona, perché la shell espande la variabile e la sostituzione del comando prima di chiamare l' cdintegrato, in modo che cdriceva il valore di ${HOME}come argomento.

Sistemi POSIX fare avere un binario cd- sulla mia macchina FreeBSD, è a /usr/bin/cd, ma non fa quello che si pensa. Chiamare il binario cdfa sì che la shell esegua il fork / exec del binario, che in effetti cambia la sua directory di lavoro con il nome che passi. Tuttavia, non appena lo fa, il binario si chiude e il processo biforcato / eseguito scompare, riportandoti alla tua shell, che è ancora nella directory in cui si trovava prima di iniziare.



23

cdnon legge l'input standard. Ecco perché il tuo primo esempio non funziona.

xargsha bisogno di un nome di comando, cioè un nome di un eseguibile indipendente. cddeve essere un comando incorporato della shell e non avrebbe alcun effetto (a parte la verifica che è possibile passare a quella directory e i potenziali effetti collaterali che potrebbe avere per le directory automountable) se fosse un eseguibile. Ecco perché il tuo secondo esempio non funziona.


4

Oltre alla buona risposta esistente, vale anche la pena ricordare che una pipe esegue un nuovo processo, che ha una propria directory di lavoro separata. Pertanto, cercando di farlo, non funzionerà:

echo test | cd /

Quindi, non sarai nella cartella / dopo che la shell tornerà da questo comando.


Tutti i comandi in una pipeline vengono eseguiti in processi diversi, quindi a | b, anche se ae bsono integrati, almeno uno non viene eseguito nel processo di shell, ma non esiste alcuna garanzia su quale sia. Ad esempio in AT&T ksh, zsho bash -O lastpipe, bviene eseguito nel processo di shell corrente, quindi il tuo codice ti porterebbe a / lì.
Stéphane Chazelas,

4

Oltre alle risposte corrette già fornite: se esegui bash e vuoi scoprire che cos'è un "comando" come cd puoi usare type

$ type cd
cd is a shell builtin

o perché no:

$ type time
time is a shell keyword

mentre ad esempio gnu time è normalmente già incluso nella tua distribuzione preferita:

$ which time
/usr/bin/time

Okey okey hai avuto l'idea, allora che diamine è di tipo?

$ type type
type is a shell builtin

Ecco un frammento manuale di bash:

       type [-aftpP] name [name ...]
          With no options, indicate how each name would be interpreted  if  used  as  a
          command name.  If the -t option is used, type prints a string which is one of
          alias, keyword, function, builtin,  or  file  if  name  is  an  alias,  shell
          reserved word, function, builtin, or disk file, respectively.  If the name is
          not found, then nothing is printed, and an exit status of false is  returned.
          If  the -p option is used, type either returns the name of the disk file that
          would be executed if name were specified as a command  name,  or  nothing  if
          ‘‘type  -t  name’’ would not return file.  The -P option forces a PATH search
          for each name, even if ‘‘type -t name’’ would not return file.  If a  command
          is  hashed,  -p  and -P print the hashed value, not necessarily the file that
          appears first in PATH.  If the -a option is used,  type  prints  all  of  the
          places  that  contain  an  executable  named name.  This includes aliases and
          functions, if and only if the -p option is  not  also  used.   The  table  of
          hashed  commands  is  not  consulted when using -a.  The -f option suppresses
          shell function lookup, as with the command builtin.  type returns true if any
          of the arguments are found, false if none are found.

0

Come altri hanno già detto, non funzionerà perché cdè un comando incorporato della shell, non un programma esterno, quindi non ha alcun input standard in cui è possibile reindirizzare nulla.

Ma, anche se funzionasse, non farebbe ciò che desideri: una pipe genera un nuovo processo e reindirizza l'output standard del primo comando nell'input standard del secondo, quindi solo il nuovo processo cambierebbe il suo funzionamento attuale directory; questo non ha potuto influire in alcun modo sul primo processo.


2
Il tuo secondo paragrafo è giusto. Ma per quanto riguarda il primo paragrafo: perché pensi che i builtin della shell non abbiano stdin? readdi solito è (sempre?) una shell integrata. È vero che cdignora lo stdin, ma ciò non è dovuto al fatto che è incorporato.
dubiousjim,

-2

Un'altra opzione sono i backtick, che posizionano lo stdout di un comando come argomento della riga di comando di un secondo comando e sono più portabili di $(...). Per esempio:

cd `echo $HOME`

o più in generale;

cd `anycommand -and whatever args`

Si noti che l'uso di backtick dipende dalla shell per l'esecuzione del comando e la sostituzione dell'output sulla riga di comando. La maggior parte delle shell lo supporta.


3
L'OP ha già dichiarato, nella sua domanda, che $(...)funziona. Non penso che sia un buon consiglio raccomandare invece i backtick, poiché hanno regole di quotazione molto più contorte e sono generalmente più soggette a errori. (Vedi §3.5.4 "Sostituzione comandi" nel Manuale di riferimento di Bash .)
Ruakh

$ () è utile laddove supportato, ma i backtick sono più ampiamente supportati su diverse shell e sistemi. Ma dovrei riformularlo come "un'altra opzione".
Seth Noble,

Conchiglie diverse, sì; ma diversi "sistemi"? Ci sono davvero delle shell che supporteranno $(...)su un sistema ma non su un altro ??
Ruakh,

4
-1, non risponde affatto alla domanda.
Bernhard,

3
@ruakh & Seth: supporto di tutte le shell POSIX $(…). I sistemi senza una shell POSIX (cioè con una shell Bourne originale) sarebbero estremamente vecchi. Anche i sistemi in cui /bin/shè presente una shell Bourne ed è necessario un altro percorso, ad esempio /usr/xpg4/bin/shper ottenere una shell POSIX, sono rari al giorno d'oggi. Raccomandare backtick a chiunque non amministri professionalmente unix boxen antico sta facendo loro un disservizio.
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.