ความแตกต่างระหว่างdu -sh *
และdu -sh ./*
คืออะไร
หมายเหตุ: สิ่งที่ฉันสนใจคือ*
และ./*
ชิ้นส่วน
ความแตกต่างระหว่างdu -sh *
และdu -sh ./*
คืออะไร
หมายเหตุ: สิ่งที่ฉันสนใจคือ*
และ./*
ชิ้นส่วน
คำตอบ:
$ touch ./-c $ 'a \ n12 \ tb' foo $ du -hs * 0 ก 12 b 0 foo 0 ทั้งหมด
อย่างที่คุณเห็น-c
ไฟล์ถูกใช้เป็นตัวเลือกdu
และไม่ถูกรายงาน (และคุณเห็นtotal
บรรทัดเนื่องจากdu -c
) นอกจากนี้ไฟล์ที่เรียกว่าa\n12\tb
จะทำให้เราคิดว่ามีไฟล์ที่เรียกว่าและa
b
$ du -hs -- *
0 a
12 b
0 -c
0 foo
นั่นดีกว่า. อย่างน้อยคราว-c
นี้ไม่ได้เป็นตัวเลือก
$ du -hs ./*
0 ./a
12 b
0 ./-c
0 ./foo
นั่นดีกว่า ./
ป้องกันคำนำหน้า-c
จากการถูกนำมาเป็นตัวเลือกและกรณีที่ไม่มี./
มาก่อนb
ในการส่งออกบ่งชี้ว่าไม่มีb
ไฟล์ในนั้น แต่มีไฟล์ที่มีตัวอักษรขึ้นบรรทัดใหม่ ( แต่ดูด้านล่าง1สำหรับ digressions เพิ่มเติมเกี่ยวกับที่)
มันเป็นวิธีที่ดีที่จะใช้./
คำนำหน้าเมื่อเป็นไปได้และหากไม่ได้และข้อมูลโดยพลการที่คุณควรเสมอใช้:
cmd -- "$var"
หรือ:
cmd -- $patterns
หากcmd
ไม่รองรับ--
การทำเครื่องหมายจุดสิ้นสุดของตัวเลือกคุณควรรายงานว่าเป็นข้อผิดพลาดต่อผู้เขียน (ยกเว้นเมื่อมีตัวเลือกและจัดทำเอกสารเช่นecho
)
มีหลายกรณีที่./*
แก้ปัญหาที่--
ไม่เป็น ตัวอย่างเช่น
awk -f file.awk -- *
ล้มเหลวหากมีไฟล์ที่เรียกว่าa=b.txt
ในไดเรกทอรีปัจจุบัน (ตั้งค่าตัวแปร awk a
เป็นb.txt
แทนที่จะบอกให้ประมวลผลไฟล์)
awk -f file.awk ./*
ไม่มีปัญหาเนื่องจาก./a
ไม่ใช่ชื่อตัวแปร awk ที่ถูกต้องดังนั้นจึง./a=b.txt
ไม่ถือเป็นการกำหนดตัวแปร
cat -- * | wc -l
ล้มเหลวหากมีไฟล์ที่เรียกว่า-
ในไดเรกทอรีปัจจุบันตามที่บอกcat
ให้อ่านจาก stdin ( -
เป็นพิเศษกับยูทิลิตี้การประมวลผลข้อความส่วนใหญ่และถึงcd
/ pushd
)
cat ./* | wc -l
เป็นเพราะตกลงไม่ได้เป็นพิเศษเพื่อ./-
cat
สิ่งที่ชอบ:
grep -l -- foo *.txt | wc -l
เพื่อนับจำนวนไฟล์ที่มีfoo
ผิดเนื่องจากถือว่าชื่อไฟล์ไม่มีอักขระขึ้นบรรทัดใหม่ ( wc -l
นับอักขระขึ้นบรรทัดใหม่เอาต์พุตเหล่านั้นโดยgrep
สำหรับแต่ละไฟล์และไฟล์ในชื่อไฟล์เอง) คุณควรใช้แทน:
grep -l foo ./*.txt | grep -c /
(การนับจำนวน/
ตัวอักษรมีความน่าเชื่อถือมากกว่าเนื่องจากมีเพียงหนึ่งชื่อไฟล์เท่านั้น)
สำหรับการเรียกซ้ำgrep
จะใช้กลอุบายที่เทียบเท่ากัน:
grep -rl foo .//. | grep -c //
./*
อาจมีผลข้างเคียงที่ไม่พึงประสงค์
cat ./*
เพิ่มอักขระอีกสองตัวต่อไฟล์ดังนั้นจะทำให้คุณมีขนาดถึงขีด จำกัด สูงสุดของข้อโต้แย้ง + สภาพแวดล้อมในไม่ช้า และบางครั้งคุณไม่ต้องการ./
ให้มีการรายงานในผลลัพธ์ ชอบ:
grep foo ./*
จะส่งออก:
./a.txt: foobar
แทน:
a.txt: foobar
1 . ฉันรู้สึกว่าฉันต้องขยายที่นี่ตามการอภิปรายในความคิดเห็น
$ du -hs ./*
0 ./a
12 b
0 ./-c
0 ./foo
ด้านบนการ./
ทำเครื่องหมายจุดเริ่มต้นของแต่ละไฟล์หมายความว่าเราสามารถระบุได้อย่างชัดเจนว่าชื่อไฟล์แต่ละไฟล์เริ่มต้นที่ (ที่./
) และที่ใดที่สิ้นสุด (ที่ขึ้นบรรทัดใหม่ก่อนหน้าถัดไป./
หรือตอนท้ายของเอาต์พุต)
สิ่งที่หมายถึงคือการส่งออกของdu ./*
ซึ่งตรงกันข้ามกับของdu -- *
) สามารถแยกได้อย่างน่าเชื่อถือแม้ว่าจะไม่ได้อย่างง่ายดายในสคริปต์
เมื่อเอาต์พุตไปยังเทอร์มินัลมีหลายวิธีที่ชื่อไฟล์อาจหลอกคุณ:
\r
เลื่อนเคอร์เซอร์ไปที่จุดเริ่มต้นของบรรทัด\b
เลื่อนเคอร์เซอร์กลับ\e[C
ไปข้างหน้า (ในเทอร์มินัลส่วนใหญ่) ...มีอักขระ Unicode ที่มีลักษณะเหมือนกับเครื่องหมายทับในแบบอักษรส่วนใหญ่
$ printf '\u002f \u2044 \u2215 \u2571 \u29F8\n'
/ ⁄ ∕ ╱ ⧸
(ดูว่ามันทำงานอย่างไรในเบราว์เซอร์ของคุณ)
ตัวอย่าง:
$ touch x 'x ' $'y\bx' $'x\n0\t.\u2215x' $'y\r0\t.\e[Cx'
$ ln x y
$ du -hs ./*
0 ./x
0 ./x
0 ./x
0 .∕x
0 ./x
0 ./x
มีจำนวนมากx
แต่y
ขาดหายไป
เครื่องมือบางอย่างเช่นGNU
ls จะแทนที่อักขระที่ไม่สามารถพิมพ์ได้ด้วยเครื่องหมายคำถาม (โปรดทราบว่า∕
(U + 2215) สามารถพิมพ์ได้) เมื่อเอาต์พุตไปที่เทอร์มินัล GNU du
ทำไม่ได้
มีวิธีที่จะทำให้พวกเขาเปิดเผยตัวเอง:
$ ls
x x x?0?.∕x y y?0?.?[Cx y?x
$ LC_ALL=C ls
x x?0?.???x x y y?x y?0?.?[Cx
ดูวิธีการ∕
หันไป???
หลังจากที่เราบอกls
ว่าชุดตัวละครของเราเป็น ASCII
$ du -hs ./* | LC_ALL=C sed -n l
0\t./x$
0\t./x $
0\t./x$
0\t.\342\210\225x$
0\t./y\r0\t.\033[Cx$
0\t./y\bx$
$
ทำเครื่องหมายจุดสิ้นสุดของบรรทัดดังนั้นเราจึงสามารถมองเห็น"x"
vs "x "
, อักขระที่ไม่สามารถพิมพ์ได้และอักขระที่ไม่ใช่ ASCII ทั้งหมดแสดงด้วยเครื่องหมายแบ็กสแลช (แบ็กสแลชเองจะถูกแสดงด้วยเครื่องหมายแบ็กสแลชสองตัว) นั่นคือ GNU sed
มันควรจะเหมือนกันในทุกsed
การใช้งานที่เป็นไปตาม POSIX แต่โปรดทราบว่าsed
การใช้งานแบบเก่าบางอย่างไม่เป็นประโยชน์
$ du -hs ./* | cat -vte
0^I./x$
0^I./x $
0^I./x$
0^I.M-bM-^HM-^Ux$
(ไม่ใช่แบบมาตรฐาน แต่ค่อนข้างธรรมดาและcat -A
มีการใช้งานบางอย่าง) อันนั้นมีประโยชน์และใช้การเป็นตัวแทนที่แตกต่างกัน แต่ไม่ชัดเจน ( "^I"
และ<TAB>
จะแสดงเช่นเดียวกัน)
$ du -hs ./* | od -vtc
0000000 0 \t . / x \n 0 \t . / x \n 0 \t .
0000020 / x \n 0 \t . 342 210 225 x \n 0 \t . / y
0000040 \r 0 \t . 033 [ C x \n 0 \t . / y \b x
0000060 \n
0000061
อันนั้นเป็นมาตรฐานและไม่คลุมเครือ (และสอดคล้องกันจากการนำไปใช้กับการนำไปใช้) แต่ไม่ง่ายที่จะอ่าน
คุณจะสังเกตเห็นว่าy
ไม่เคยปรากฏขึ้นด้านบน นั่นเป็นปัญหาที่ไม่เกี่ยวข้องอย่างสมบูรณ์กับdu -hs *
สิ่งที่ไม่เกี่ยวข้องกับชื่อไฟล์ แต่ควรจดบันทึก: เนื่องจากdu
รายงานการใช้งานดิสก์มันจะไม่รายงานลิงก์อื่น ๆ ไปยังไฟล์ที่แสดงรายการอยู่แล้ว ( du
การใช้งานไม่ได้ทั้งหมดจะมีพฤติกรรมเช่นนั้น บนบรรทัดคำสั่ง)
[a-z0-9.+-]
จำกัด
/tmp
) หรือพื้นที่ที่มีรถยนต์ราคาแพงจำนวนมาก ( $HOME
) และยิ่งแย่ไปกว่านั้นถ้าคุณไปที่ไซต์ถาม - ตอบและบอกว่าไม่เป็นไรที่จะล็อครถของคุณโดยไม่ต้องระบุเงื่อนไขใด ๆ คุณเขียนทำงานด้วยตัวเองเพียงบนเครื่องไม่ได้เชื่อมต่อกับเครือข่ายใด ๆ หรือการเก็บข้อมูลแบบถอด ... )
"b "
หรือ"a\bb"
) จะหลอกผู้ใช้บนขั้ว du ./*
แต่ไม่สคริปต์แยกการส่งออกของ ฉันควรจะเพิ่มบันทึกเกี่ยวกับเรื่องนั้น จะทำในวันพรุ่งนี้ โปรดทราบว่าก่อนหน้านี้ฉันหมายถึงเอกสิทธิ์ในความหมายทั่วไปไม่ใช่root
(แม้ว่าจะใช้กับทุกอย่างมากขึ้นroot
แน่นอน) อนุญาตให้ขึ้นบรรทัดใหม่ได้โดยไม่สนใจว่าเป็นข้อบกพร่อง ข้อบกพร่องมีนิสัยที่ถูกเอาเปรียบ คุณต้องวัดความเสี่ยงเป็นราย ๆ ไป การฝึกการเขียนโปรแกรมที่ดีสามารถหลีกเลี่ยงปัญหาในหลาย ๆ กรณี แน่นอนเกี่ยวกับ SE เราควรสร้างความตระหนัก
ไม่มีความแตกต่างระหว่าง a *
และ./*
ในแง่ของสิ่งที่ไฟล์จะแสดงรายการ ความแตกต่างเพียงอย่างเดียวคือในรูปแบบที่ 2 แต่ละไฟล์จะมีจุดทับ./
ด้านหน้านำหน้าซึ่งโดยทั่วไปหมายถึงไดเรกทอรีปัจจุบัน
จำไว้ว่า.
ไดเรกทอรีนั้นเป็นรูปแบบย่อของไดเรกทอรีปัจจุบัน
$ ls -la | head -4
total 28864
drwx------. 104 saml saml 12288 Jan 23 20:04 .
drwxr-xr-x. 4 root root 4096 Jul 8 2013 ..
-rw-rw-r--. 1 saml saml 972 Oct 6 20:26 abcdefg
คุณสามารถโน้มน้าวใจตัวเองว่า 2 รายการเหล่านี้เป็นสิ่งเดียวกันโดยใช้echo
เพื่อดูว่าเชลล์จะขยายไปยังอะไร
$ echo *
$ echo ./*
คำสั่ง 2 เหล่านี้จะแสดงรายการไฟล์ทั้งหมดในไดเรกทอรีปัจจุบันของคุณ
เราสามารถสร้างข้อมูลปลอมบางอย่างเช่น:
$ touch file{1..5}
$ ll
total 0
-rw-rw-r--. 1 saml saml 0 Jan 24 07:14 file1
-rw-rw-r--. 1 saml saml 0 Jan 24 07:14 file2
-rw-rw-r--. 1 saml saml 0 Jan 24 07:14 file3
-rw-rw-r--. 1 saml saml 0 Jan 24 07:14 file4
-rw-rw-r--. 1 saml saml 0 Jan 24 07:14 file5
ตอนนี้เมื่อเราใช้echo
คำสั่งข้างต้นเราจะเห็นผลลัพธ์ต่อไปนี้:
$ echo *
file1 file2 file3 file4 file5
$ echo ./*
./file1 ./file2 ./file3 ./file4 ./file5
ความแตกต่างนี้อาจดูไม่จำเป็น แต่ก็มีหลายสถานการณ์ที่คุณต้องการรับประกันให้กับเครื่องมือบรรทัดคำสั่ง Unix ต่างๆที่คุณส่งชื่อไฟล์ผ่านทางบรรทัดคำสั่งและไม่มีอะไรเพิ่มเติม!
เมื่อคำตอบของ @ Stephane ชี้ให้เห็นเนื่องจากลักษณะของอักขระที่ถูกกฎหมายเมื่อตั้งชื่อไฟล์และไดเรกทอรีใน Unix ชื่อไฟล์ที่เป็นอันตรายสามารถสร้างขึ้นได้ซึ่งมีผลข้างเคียงที่ไม่คาดคิดเมื่อพวกมันถูกส่งไปยังคำสั่ง Unix ต่างๆ
บ่อยครั้งที่การใช้งาน./
จะถูกใช้เพื่อช่วยรับประกันว่าชื่อไฟล์ที่ขยายจะถือว่าเป็นชื่อไฟล์เมื่อส่งผ่านเป็นอาร์กิวเมนต์ไปยังคำสั่ง Unix ต่างๆ