web-dev-qa-db-ja.com

「xargsls」を並列実行すると出力が文字化けする

lsを使用して/usr/内のすべてのファイルを一覧表示したいと思います。 lsを直接呼び出すのではなく、xargsを介して呼び出します。さらに、xargsパラメーター-Lおよび-Pを使用して、すべてのコアを利用しています。

find /usr/ -type f  -print0 | xargs -0 -L16 -P4 ls -lAd  | sort -k9 > /tmp/aaa

上記のコマンドは期待どおりに機能します。それは素晴らしい出力を生成します。ただし、行数-Lパラメーターを16から64に増やすと、次のようになります。

find /usr/ -type f  -print0 | xargs -0 -L64 -P4 ls -lAd  | sort -k9 > /tmp/bbb

結果の出力はすべて文字化けします。つまり、出力は新しい行で開始されなくなり、新しい行は「前の」行の途中で開始され、すべて混同されます。

-rw-r--r-- 1 root root  5455 Nov 16  2010 /usr/shareonts/X11/encodings/armscii-8.enc.gz
-rw-r--r-- 1 root root  1285 May 29  2016-rw-r--r-- 1 root root   6205 May 29  2016 /usr/include/arpa/nameser_compat.h
-rw-r--r-- 1 root root       0 Apr 17  20-rw-r--r-- 1 root root   933 Apr 16  2012 /usr/share/icons/nuoveXT2/16x16/actions/address-book-new.png
-rw-r--r-- 1 root root  53651 Jun 17  2012-rw-r--r-- 1 root root  7117 May 29  2016 /usr/include/dlfcn.h
-rw-r--r-- 1 root root  311 Jun  9  2015-rw-r--r-- 1 root root 1700 Jun  9  2015 /usr/share/cups/templates/de/add-printer.tmpl
-rw-r--r-- 1 root root  5157 M1 root root 10620 Jun 14  2012 /usr/lib/Perl5/Tk/pTk/tkIntXlibDecls.m
-rw-r--r-- 1 root -rwxr-xr-x 1 root root    1829 Jan 22  2013 /usr/lib/emacsen-common/packages/install/dictionaries-common
-rw-r--r-- 1 root r-rw-r--r-- 1 root root  1890 Jun  2  2012 /usr/share/Perl5/Date/Manip/TZ/afaddi00.pm
-rw-r--r-- 1 root root 1104 Jul-rw-r--r-- 1 root root  10268 Jul 27 15:58 /usr/share/Perl/5.14.2/B/Debug.pm
-rw-r--r-- 1 root root  725 Apr  1-rw-r--r-- 1 root root  883 Apr  1  2012 /usr/share/icons/gnome/16x16/actions/address-book-new.png

面白いことに、それは-L64以上を使用している場合にのみ発生します。 -L16ではこの問題は発生しません。

誰かがここで何が起こっているのか説明できますか?

5
Martin Vegter

これは、パイプへの書き込みと関係があります。 -L16を使用すると、16個のファイルごとに1つのプロセスを実行します。これにより、ファイル名の長さにもよりますが、約1,000文字が生成されます。 -L64を使用すると、約4,000人になります。 lsプログラムは、ほぼ確実にstdioライブラリを使用し、ほぼ確実に、書き込み呼び出しの数を減らすために出力に4kBバッファを使用します。

したがって、findはファイル名のロードを生成し、(-L64の場合)xargsはそれらを64のバンドルに切り刻み、4つのlsプロセスを起動してそれらを処理します。各lsは、最初の4kの出力を生成し、それをパイプに書き込んでソートします。この4kは通常not改行で終わることに注意してください。つまり、3番目のlsが最初の4kBを最初に準備し、それが終了するとします。

 lrwxrwxrwx 1 root root       6 Oct 21  2013 bzegrep -> bzgrep
 -rwxr-xr-x 1 root root    4877 Oct 21  2013 bzexe
 lrwxrwxrwx 1 root root       6 Oct 2

次に、最初のlsは何かを出力します。

 total 123459

その場合、ソートする入力にはlrwxrwxrwx 1 root root 6 Oct 2total 123459が含まれます。

-L16の場合、lsプロセスは(通常)一度に結果の完全なセットのみを出力します。

もちろん、この場合、xargsとlsを使用して時間とリソースを浪費しているだけなので、追加のプログラムを実行して情報を再度検出するのではなく、findにすでに持っている情報を出力させる必要があります。

5
icarus

GNU Parallelは、ミキシングの問題(実行時間40秒)を正確に解決するために構築されました。

find /usr/ -type f  -print0 | parallel -0 -L64 -P4 ls -lAd  | sort -k9 > /tmp/bbb

コアの数(実行時間40秒)も検出できます。

find /usr/ -type f -print0 | parallel -0 -L64 ls -lAd  | sort -k9 > /tmp/bbb

そして、入力を均等に分割します(実行時間24秒):

find /usr/ -type f -print0 | parallel -0 -X ls -lAd  | sort -k9 > /tmp/bbb
1
Ole Tange