Pourquoi `watch` crée-t-il le contenu de la liste` ls / tmp` de $ HOME?

13

J'essaie de regarder le nombre de fichiers dans mon /tmp/répertoire. Pour cela, je pensais que cette commande fonctionnerait:

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

Mais cela semble fonctionner comme s'il lsn'avait pas d'arguments. A savoir, je suis ~dedans, et j'y reçois un certain nombre de fichiers au lieu de /tmp/. J'ai trouvé une solution de contournement, qui semble fonctionner:

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

Mais pourquoi dois-je échapper à l'espace entre lset /tmp/? Comment la commande est-elle transformée par watchafin que la lssortie soit alimentée wc, mais /tmp/ne soit pas passée en argument ls?

Ruslan
la source
1
watch "sh -c 'ls /tmp | wc -l'"l'exécution de cette commande devrait obtenir l'effet souhaité. Ce n'est pas la faute des montres, essayez sh -c ls /tmpet vous obtiendrez votre répertoire personnel (mais je ne sais pas pourquoi ...)
Jacob Minshall
8
Pas une réponse , mais vous utilisez watchcorrectement .La commande que vous passez à watchest à son tour alimenté par watchde sh -c, vous êtes en effet faire sh -cdeux fois.
iruvar
Si vous êtes curieux, vous pouvez également consulter la source .
michas
1
@JacobMinshall, le pourquoi est simple: le /tmpest un argument pour sh, dans ce cas, pas un argument pour ls.
Charles Duffy

Réponses:

17

La différence peut être vue via 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

Dans le cas de la citation arrière, ls /tmpest passé en tant qu'argument unique au -cto sh, qui s'exécute comme prévu. Sans cette citation inverse, la commande est plutôt divisée en mots lors de l' watchexécution shqui à son tour exécute le fourni sh, de sorte que seul lsest passé comme argument à-c , ce qui signifie que le sous-sous- shprogramme exécutera uniquement une lscommande nue et répertorie le contenu du travail en cours annuaire.

Alors, pourquoi la complication sh -c ...? Pourquoi ne pas simplement courir watch 'ls /tmp|wc -l'?

branler
la source
Oh en effet, je n'ai pas pensé à essayer strace.
Ruslan
1
En fait, `est backquote (ou back-tick). Cette question concerne \, qui est une barre oblique inverse.
G-Man dit `` Réintègre Monica '' le
@Ruslan: J'ai posté ce commentaire sur cette réponse car c'est un commentaire sur cette réponse . thrig dit « Dans le backquote cas, ls /tmpest ... » et « Sans cette backquote , la commande est ... », et les utilisations bqet nobqles noms de fichiers, lorsque tout en se référant à la barre oblique inverse dans votre ls\ /tmpcommande.
G-Man dit `` Réintègre Monica '' le
8

Il existe deux catégories principales de watchcommandes (celles qui doivent exécuter des commandes périodiquement, watchn'est pas une commande standard, il existe même des systèmes oùwatch quelque chose de complètement différent comme espionner sur une autre ligne tty sur FreeBSD).

Celui qui transmet déjà la concaténation de ses arguments avec des espaces à un shell (il fait en fait appel sh -c <concatenation-of-arguments>) et celui qui exécute simplement la commande spécifiée avec les arguments spécifiés sans invoquer de shell.

Vous êtes dans la première situation, il vous suffit donc:

watch 'ls /tmp/|wc -l'

Quand vous faites:

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

votre watchfonctionne réellement:

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

Et sh -c ls /tmp/exécute le lsscript en ligne où $0est /tmp/(doncls est exécuté sans arguments et répertorie le répertoire actuel).

Certaines des watchimplémentations de la première catégorie (comme celle de procps-ng sous Linux) acceptent une -xoption pour les faire se comporter comme celles watchde la deuxième catégorie. Donc avec ça, vous pouvez faire:

watch -x sh -c 'ls /tmp/|wc -l'
Stéphane Chazelas
la source