Mengapa `watch` membuat` ls / tmp` daftar isi $ HOME?

13

Saya mencoba menonton sejumlah file di /tmp/direktori saya . Untuk ini saya pikir perintah ini akan berhasil:

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

Tetapi tampaknya berfungsi seolah-olah lstidak punya argumen. Yaitu, saya masuk ~, dan saya mendapatkan jumlah file di sana, bukan /tmp/. Saya menemukan solusi, yang tampaknya berhasil:

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

Tetapi mengapa saya harus lari dari ruang antara lsdan /tmp/? Bagaimana perintah diubah oleh watchsehingga lsoutput diumpankan wc, tetapi /tmp/tidak diteruskan sebagai argumen ls?

Ruslan
sumber
1
watch "sh -c 'ls /tmp | wc -l'"melakukan perintah ini harus mendapatkan efek yang diinginkan. Ini bukan kesalahan jam tangan, cobalah sh -c ls /tmpdan Anda akan mendapatkan direktori rumah Anda (tapi saya tidak tahu mengapa ...)
Jacob Minshall
8
Bukan jawaban tetapi Anda menggunakan watchsalah. Perintah yang Anda berikan watchpada gilirannya diumpankan watchke sh -c, jadi Anda sebenarnya melakukan sh -cdua kali.
iruvar
Jika Anda penasaran, Anda juga dapat melihat sumbernya .
michas
1
@ JacobMinshall, alasannya mudah: /tmpArgumen untuk sh, dalam hal ini, bukan argumen untuk ls.
Charles Duffy

Jawaban:

17

Perbedaannya dapat dilihat melalui 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

Dalam kasus backquote, ls /tmpdilewatkan sebagai argumen tunggal ke -cke sh, yang berjalan seperti yang diharapkan. Tanpa backquote ini, perintahnya adalah kata split ketika watchmenjalankan shyang pada gilirannya menjalankan yang disediakan sh, sehingga hanya lsditeruskan sebagai argumen -c, yang berarti bahwa sub-sub shhanya akan menjalankan lsperintah kosong , dan daftar isi dari pekerjaan saat ini direktori.

Jadi, mengapa komplikasi sh -c ...? Kenapa tidak lari saja watch 'ls /tmp|wc -l'?

thrig
sumber
Oh, memang, tidak terpikir untuk stracemencobanya.
Ruslan
1
Sebenarnya, `adalah backquote (atau back-tick). Pertanyaan ini tentang \, yang merupakan garis miring terbalik.
G-Man Mengatakan 'Reinstate Monica'
@Ruslan: Saya memposting komentar ini pada jawaban ini karena ini adalah komentar untuk jawaban ini . thrig mengatakan "Dalam kasus backquote , ls /tmpadalah ..." dan "Tanpa backquote ini , perintahnya adalah ...", dan menggunakan bqdan nobqsebagai nama file, ketika semua mengacu pada backslash dalam ls\ /tmpperintah Anda .
G-Man Mengatakan 'Reinstate Monica'
8

Ada dua kategori utama watchperintah (dari yang menjalankan perintah secara berkala, watchbukan perintah standar, bahkan ada sistem di mana watchmelakukan sesuatu yang sangat berbeda seperti mengintip pada baris tty lain di FreeBSD).

Salah satu yang sudah melewati rangkaian argumennya dengan spasi ke shell (itu tidak berlaku panggilan sh -c <concatenation-of-arguments>) dan yang hanya menjalankan perintah yang ditentukan dengan argumen yang ditentukan tanpa memanggil shell.

Anda berada dalam situasi pertama, jadi Anda hanya perlu:

watch 'ls /tmp/|wc -l'

Saat kamu melakukan:

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

Anda watchbenar - benar berjalan:

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

Dan sh -c ls /tmp/menjalankan lsskrip inline mana $0yang /tmp/(jadi lsdijalankan tanpa argumen dan daftar direktori saat ini).

Beberapa watchimplementasi dalam kategori pertama (seperti yang dari procps-ng di Linux) menerima -xopsi untuk membuat mereka berperilaku seperti yang watchdari kategori kedua. Jadi dengan itu, Anda bisa melakukan:

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