Perché `watch` fa in modo che` ls / tmp` elenchi i contenuti di $ HOME?


13

Sto provando a guardare il numero di file nella mia /tmp/directory. Per questo ho pensato che questo comando avrebbe funzionato:

watch sh -c 'ls /tmp/|wc -l'

Ma sembra funzionare come se lsnon avesse argomenti. Vale a dire, ci sono ~e ottengo un numero di file lì invece di /tmp/. Ho trovato una soluzione alternativa, che sembra funzionare:

watch sh -c 'ls\ /tmp/|wc -l'

Ma perché devo fuggire dallo spazio tra lse /tmp/? In che modo viene trasformato il comando in watchmodo che l' lsoutput sia alimentato wc, ma /tmp/non venga passato come argomento a ls?


1
watch "sh -c 'ls /tmp | wc -l'"eseguire questo comando dovrebbe ottenere l'effetto desiderato. Non è colpa degli orologi, prova sh -c ls /tmpe otterrai la tua home directory (ma non ho idea del perché ...)
Jacob Minshall,

8
Non è una risposta, ma che si sta utilizzando watchin modo non corretto .Il comando che si passa a watchè a sua volta alimentato da watcha sh -c, quindi sei in effetti facendo sh -cdue volte.
Iruvar,

Se sei curioso puoi anche dare un'occhiata alla fonte .
michas,

1
@JacobMinshall, il perché è semplice: Il /tmpè un argomento per sh, in questo caso, non è un argomento per ls.
Charles Duffy,

Risposte:


17

La differenza può essere vista tramite strace:

$ strace -ff -o bq watch sh -c 'ls\ /tmp/|wc -l'
^C
$ strace -ff -o nobq watch sh -c 'ls /tmp/|wc -l'
^C
$ grep exec bq* | grep sh
bq.29218:execve("/usr/bin/watch", ["watch", "sh", "-c", "ls\\ /tmp/|wc -l"], [/* 54 vars */]) = 0
bq.29219:execve("/bin/sh", ["sh", "-c", "sh -c ls\\ /tmp/|wc -l"], [/* 56 vars */]) = 0
bq.29220:execve("/bin/sh", ["sh", "-c", "ls /tmp/"], [/* 56 vars */]) = 0
$ grep exec nobq* | grep sh
nobq.29227:execve("/usr/bin/watch", ["watch", "sh", "-c", "ls /tmp/|wc -l"], [/* 54 vars */]) = 0
nobq.29228:execve("/bin/sh", ["sh", "-c", "sh -c ls /tmp/|wc -l"], [/* 56 vars */]) = 0
nobq.29229:execve("/bin/sh", ["sh", "-c", "ls", "/tmp/"], [/* 56 vars */]) = 0

Nel caso del backquote, ls /tmpviene passato come singolo argomento al -cto sh, che viene eseguito come previsto. Senza questo backquote, il comando è invece suddiviso in parole quando watchviene eseguito shche a sua volta esegue il fornito sh, in modo che lsvenga passato solo come argomento a -c, il che significa che il sub-sub sheseguirà solo un lscomando nudo ed elenca il contenuto del funzionamento corrente directory.

Quindi, perché la complicazione di sh -c ...? Perché non semplicemente correre watch 'ls /tmp|wc -l'?


Oh davvero, non ho pensato di provarci strace.
Ruslan,

1
In realtà, `è backquote (o back-tick). Questa domanda riguarda \, che è una barra rovesciata.
G-Man dice "Ripristina Monica" il

@Ruslan: ho pubblicato questo commento su questa risposta perché è un commento su questa risposta . thrig dice "Nel caso del backquote , ls /tmpè ..." e "Senza questo backquote , il comando è ..." e usa bqe nobqcome nomi di file, quando nel frattempo si riferisce alla barra rovesciata nel ls\ /tmpcomando.
G-Man dice "Ripristina Monica" il

8

Ci sono due principali categorie di watchcomandi (di quelli che devono eseguire comandi periodicamente, watchnon è un comando standard, ci sono persino sistemi in cui watchfa qualcosa di completamente diverso come curiosare su un'altra linea tty su FreeBSD).

Uno che passa già la concatenazione dei suoi argomenti con spazi a una shell (in effetti chiama sh -c <concatenation-of-arguments>) e uno che esegue semplicemente il comando specificato con gli argomenti specificati senza invocare una shell.

Sei nella prima situazione, quindi hai solo bisogno di:

watch 'ls /tmp/|wc -l'

Quando lo fai:

watch sh -c 'ls /tmp/|wc -l'

il tuo watcheffettivamente funziona:

sh -c 'sh -c ls /tmp/|wc -l'

Ed sh -c ls /tmp/esegue lo lsscript inline dove si $0trova /tmp/(quindi lsviene eseguito senza argomenti ed elenca la directory corrente).

Alcune delle watchimplementazioni nella prima categoria (come quella di procps-ng su Linux) accettano -xun'opzione per farle comportare come quelle watchdella seconda categoria. Quindi con lì, puoi fare:

watch -x sh -c 'ls /tmp/|wc -l'
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.