/tmp/
ディレクトリ内のファイルの数を監視しようとしています。このため、私はこのコマンドが機能すると思いました:
watch sh -c 'ls /tmp/|wc -l'
しかし、ls
に引数がないかのように機能しているように見えます。つまり、私は~
にいて、/tmp/
の代わりにそこにファイルの数を取得します。私は回避策を見つけました、それはうまくいくようです:
watch sh -c 'ls\ /tmp/|wc -l'
しかし、なぜls
と/tmp/
の間のスペースをエスケープする必要があるのですか?コマンドはwatch
によってどのように変換されてls
出力がwc
に送られますが、/tmp/
は引数としてls
に渡されませんか?
違いは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
は単一の引数として-c
からsh
に渡され、期待どおりに実行されます。このバッククォートがないと、コマンドは代わりにwatch
がsh
を実行するときにワード分割され、次に指定されたsh
が実行されるため、ls
のみが-c
の引数。これは、sub-sub sh
が裸のls
コマンドのみを実行し、現在の作業ディレクトリの内容を一覧表示することを意味します。
では、なぜsh -c ...
の複雑さは?単にwatch 'ls /tmp|wc -l'
を実行してみませんか?
watch
コマンドには2つの主要なカテゴリがあります(コマンドを定期的に実行するもののうち、watch
は標準コマンドではなく、watch
が完全に何かを実行するシステムもありますFreeBSDの別のtty行をスヌーピングするようなものです)。
引数とスペースの連結をすでにシェルに渡しているもの(実際には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
実装の一部(Linuxのprocps-ngの実装など)は、-x
オプションを受け入れて、2番目のカテゴリのwatch
のように動作させます。そこで、次のことができます。
watch -x sh -c 'ls /tmp/|wc -l'