我從http://www.dwheeler.com/essays/filenames-in-shell.html寫了一個dululppb實用程序,因爲源代碼的鏈接被破壞了,我想嘗試學習D.我注意到它很慢(幾乎不能跟上find -print0正在傳遞它的數據,因爲它應該快得多,因爲它不需要接近任何系統調用)。爲什麼這些小型D程序的行爲有所不同?
第一個實現可以正常工作(使用zsh和bash printf內置函數以及/ usr/bin/printf進行測試)。第二種方法雖然要快得多(可能是因爲調用write()的次數要少得多),但它會多次重複其輸出的第一部分,並且無法輸出其餘部分輸出。是什麼造成這種差異?我是D的新手,不理解。
工作代碼:
import std.stdio;
import std.conv;
void main()
{
foreach (ubyte[] mybuff; chunks(stdin, 4096)) {
encodebuff (mybuff);
}
}
@safe void encodebuff (ubyte[] mybuff) {
foreach (ubyte i; mybuff) {
char b = to!char(i);
switch (i) {
case 'a': .. case 'z':
case 'A': .. case 'Z':
case '0': .. case '9':
case '/':
case '.':
case '_':
case ':': writeChar(b); break;
default: writeOctal(b); break;
case 0: writeChar ('\n'); break;
case '\\': writeString(`\\`); break;
case '\t': writeString(`\t`); break;
case '\n': writeString(`\n`); break;
case '\r': writeString(`\r`); break;
case '\f': writeString(`\f`); break;
case '\v': writeString(`\v`); break;
case '\a': writeString(`\a`); break;
case '\b': writeString(`\b`); break;
}
}
}
@trusted void writeString (string a)
{
write (a);
}
@trusted void writeOctal (int a)
{
writef ("\\%.4o", a); // leading 0 needed for for zsh printf '%b'
}
@trusted void writeChar (char a)
{
write (a);
}
破碎的版本:
import std.stdio;
import std.conv;
import std.string;
void main()
{
foreach (ubyte[] mybuff; chunks(stdin, 4096)) {
encodebuff (mybuff);
}
}
@safe void encodebuff (ubyte[] mybuff) {
char[] outstring;
foreach (ubyte i; mybuff) {
switch (i) {
case 'a': .. case 'z':
case 'A': .. case 'Z':
case '0': .. case '9':
case '/':
case '.':
case '_':
case ':': outstring ~= to!char(i); break;
case 0: outstring ~= '\n'; break;
default: char[5] mystring;
formatOctal(mystring, i);
outstring ~= mystring;
break;
case '\\': outstring ~= `\\`; break;
case '\t': outstring ~= `\t`; break;
case '\n': outstring ~= `\n`; break;
case '\r': outstring ~= `\r`; break;
case '\f': outstring ~= `\f`; break;
case '\v': outstring ~= `\v`; break;
case '\a': outstring ~= `\a`; break;
case '\b': outstring ~= `\b`; break;
}
writeString (outstring);
}
}
@trusted void writeString (char[] a)
{
write (a);
}
@trusted void formatOctal (char[] b, ubyte a)
{
sformat (b, "\\%.4o", a); // leading 0 needed for zsh printf '%b'
}
測試:(請注意,文件清單是找到-print0在我的家目錄下生成文件的NUL分隔的列表, filelist2.txt由filelist生成,由filelist.txt sed -e's/\ x0/\ n/g'> filelist2.txt生成,因此是換行符分隔的文件名的相應列表)。
# the sed script escapes the backslashes so xargs does not clobber them
diff filelist2.txt <(<filelist.txt char2code2 | sed -e 's/\\/\\\\/g' | xargs /usr/bin/printf "%b\n")
# from within zsh
bash -c 'diff filelist2.txt <(for i in "$(<filelist.txt char2code)"; do printf "%b\n" "$i"; done)'
# from within zsh and bash
diff filelist.txt <(for i in $(char2code <filelist.txt); do printf '%b\0' "$i"; done)
# from within zsh, bash, and dash
for i in $(char2code <filelist.txt); do printf '%b\0' "$i"; done | diff - filelist.txt
我作爲一個嚴峻的考驗製作的腳本:
#!/bin/bash
# this creates a completely random list of NUL-delimited strings
a=''
trap 'rm -f "$a"' EXIT
a="$(mktemp)";
</dev/urandom sed -e 's/\x0\x0/\x0/g' | dd count=2048 of="$a"
test -s "$a" || exit 1
printf '\0' >> "$a"
for i in $("[email protected]" < "$a")
do
printf '%b\0' "$i"
done | diff - "$a"
什麼是差異的原因?
編輯:我已經實施了@ yaz和@MichalMinich建議的更改,我仍然看到錯誤的結果。具體來說,找到-print0 |從我的主目錄中的char2code2(位於我的$ PATH中的程序的名稱)導致退出狀態爲1並且沒有輸出。但是,它從子目錄中運行的項目數量要少得多。新修改的源代碼如下:
import std.stdio;
import std.conv;
import std.format;
import std.array;
void main()
{
foreach (ubyte[] mybuff; chunks(stdin, 4096)) {
encodebuff (mybuff);
}
writeln();
}
void encodebuff (ubyte[] mybuff) {
auto buffer = appender!string();
foreach (ubyte i; mybuff) {
switch (i) {
case 'a': .. case 'z':
case 'A': .. case 'Z':
case '0': .. case '9':
case '/':
case '.':
case '_':
case ':': buffer.put(to!char(i)); break;
case 0: buffer.put('\n'); break;
default: formatOctal(buffer, i); break;
case '\\': buffer.put(`\\`); break;
case '\t': buffer.put(`\t`); break;
case '\n': buffer.put(`\n`); break;
case '\r': buffer.put(`\r`); break;
case '\f': buffer.put(`\f`); break;
case '\v': buffer.put(`\v`); break;
case '\a': buffer.put(`\a`); break;
case '\b': buffer.put(`\b`); break;
}
}
writeString (buffer.data);
// writef(stderr, "Wrote a line\n");
}
@trusted void writeString (string a)
{
write (a);
}
@trusted void formatOctal(Writer)(Writer w, ubyte a)
{
formattedWrite(w, "\\%.4o", a); // leading 0 needed for zsh printf '%b'
}
慕尼黑這並沒有解決問題 - 見編輯 – Demi