ความแตกต่างระหว่าง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จะทำให้เราคิดว่ามีไฟล์ที่เรียกว่าและab
$ 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ขาดหายไป
เครื่องมือบางอย่างเช่นGNUls จะแทนที่อักขระที่ไม่สามารถพิมพ์ได้ด้วยเครื่องหมายคำถาม (โปรดทราบว่า∕(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 ต่างๆ