Чому `watch` вносить` ls / tmp` вміст списку $ HOME?


13

Я намагаюся переглянути кількість файлів у своєму /tmp/каталозі. Для цього я думав, що ця команда спрацює:

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

Але, схоже, він працює так, ніби lsне мав аргументів. А саме я перебуваю там ~, і я отримую замість них кількість файлів /tmp/. Я знайшов рішення, яке, здається, працює:

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

Але чому мені потрібно уникати місця між lsі /tmp/? Як команда перетворюється на watchтак, що lsвихід подається wc, але /tmp/не передається як аргумент ls?


1
watch "sh -c 'ls /tmp | wc -l'"виконання цієї команди має отримати бажаний ефект. Це не помилка годинника, спробуйте, sh -c ls /tmpі ви отримаєте свій домашній каталог (але я поняття не маю, чому ...)
Jacob Minshall

8
Чи не відповідь , але ви використовуєте watchнеправильно .the команду, ви передаєте watchв свою чергу , харчується , watchщоб sh -c, таким чином ви фактично робите sh -cдвічі.
iruvar

Якщо вам цікаво, ви також можете подивитися на джерело .
michas

1
@JacobMinshall, чому зрозуміло: /tmpце аргумент sh, а в цьому випадку не аргумент ls.
Чарльз Даффі

Відповіді:


17

Різницю можна побачити через 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

У випадку зворотного котирування ls /tmpпередається як єдиний аргумент -cto sh, який працює як очікувалося. Без цього зворотного котирування команда замість того, щоб розділити слово під час watchзапуску, shякий, у свою чергу, виконує поставлений sh, так що lsпередається лише як аргумент -c, тобто субпідряд shвиконує лише голую lsкоманду та перелічує вміст поточної роботи каталог.

Отже, чому ускладнення sh -c ...? Чому б просто не бігти watch 'ls /tmp|wc -l'?


О, справді, не думав намагатися straceце зробити.
Руслан

1
Насправді, `зворотне котирування (або зворотне позначення). Це питання стосується \, що є зворотною косою рисою.
G-Man каже: "Відновіть Моніку"

@Ruslan: Я опублікував цей коментар до цієї відповіді, оскільки це коментар до цієї відповіді . thrig каже : «У лапки випадку, ls /tmpце ...» і «Без цієї зворотної лапки , команда ...», і використовує bqі nobqяк імена файлів, коли весь час посилаючись на зворотну косу риску в вашій ls\ /tmpкоманді.
G-Man каже: "Відновіть Моніку"

8

Існує дві основні категорії watchкоманд (з тих, які повинні запускати команди періодично, watchце не стандартна команда, є навіть системи, де watchробиться щось зовсім інше, як провішування в іншому рядку на FreeBSD).

Один, який вже передає конкатенацію своїх аргументів з пробілами в оболонку (він насправді викликає sh -c <concatenation-of-arguments>) і той, який просто виконує команду, задану аргументами, вказаними без виклику оболонки.

Ви знаходитесь в першій ситуації, тому вам просто потрібно:

watch 'ls /tmp/|wc -l'

Коли ви робите:

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

ваш watchфактично працює:

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

І sh -c ls /tmp/запускає lsвбудований скрипт, де $0є /tmp/(так lsзапускається без аргументів і перераховує поточну каталог).

Деякі з watchреалізацій першої категорії (як, наприклад, з procps-ng в Linux) приймають -xопцію, щоб змусити їх вести себе як watchінші категорії. Тож із цим можна зробити:

watch -x sh -c 'ls /tmp/|wc -l'
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.