ทำไม printf ถึงดีกว่า echo


548

ผมเคยได้ยินว่าจะดีกว่าprintf echoฉันสามารถจำได้เพียงครั้งเดียวจากประสบการณ์ที่ฉันต้องใช้printfเพราะechoไม่ได้ทำงานเพื่อป้อนข้อความบางส่วนในโปรแกรมบางโปรแกรมใน RHEL 5.8 แต่printfทำ แต่เห็นได้ชัดว่ามีความแตกต่างอื่น ๆ และฉันต้องการสอบถามว่าพวกเขาเป็นอย่างไรและมีกรณีที่เฉพาะเจาะจงเมื่อใดที่จะใช้แบบหนึ่งกับอีกแบบหนึ่ง


เกี่ยวกับecho -eอะไร
neverMind9

1
@ neverMind9 echo -eไม่ทำงานshเฉพาะในbash(ด้วยเหตุผลบางอย่าง) และนักเทียบท่าเช่นใช้เป็นshค่าเริ่มต้นสำหรับRUNคำสั่ง
Ciprian Tomoiagă

@ CiprianTomoiagă สำหรับผมที่ทำงานในเทอร์มินดรอยด์ซึ่งเป็นหลักecho -e sh
neverMind9

คำตอบ:


757

โดยทั่วไปมันเป็นปัญหาการพกพา (และความน่าเชื่อถือ)

เริ่มแรกechoไม่ยอมรับตัวเลือกใด ๆ และไม่ขยายอะไรเลย สิ่งที่มันทำทั้งหมดคือการแสดงผลอาร์กิวเมนต์ของมันคั่นด้วยอักขระเว้นวรรคและสิ้นสุดด้วยอักขระขึ้นบรรทัดใหม่

ตอนนี้มีคนคิดว่ามันจะดีถ้าเราสามารถทำสิ่งต่าง ๆ เช่นecho "\n\t"การส่งออกบรรทัดใหม่หรืออักขระแท็บหรือมีตัวเลือกที่จะไม่ส่งออกอักขระบรรทัดใหม่ต่อท้าย

จากนั้นพวกเขาคิดว่ายาก แต่แทนที่จะเพิ่มฟังก์ชันการทำงานที่เปลือก (เช่นperlที่อยู่ภายในราคาคู่\tจริงหมายถึงอักขระแท็บ) echoพวกเขาเพิ่มไปยัง

David Korn ตระหนักถึงความผิดพลาดและนำเสนอรูปแบบคำพูดใหม่ของเชลล์$'...'ซึ่งต่อมาถูกคัดลอกมาbashและในเวลาzshนั้นมันก็สายเกินไป

ตอนนี้เมื่อ UNIX มาตรฐานechoได้รับการโต้แย้งซึ่งมีอักขระสองตัว\และtแทนที่จะส่งออกมันจะส่งออกอักขระแท็บ และทันทีที่เห็น\cในอาร์กิวเมนต์มันจะหยุดการส่งออก (ดังนั้นการขึ้นบรรทัดใหม่จะไม่ได้รับผลลัพธ์เช่นกัน)

ผู้จำหน่าย / เวอร์ชั่นอื่น ๆ ของ shells / Unix เลือกที่จะทำมันแตกต่างกัน: พวกเขาเพิ่ม-eตัวเลือกในการขยายลำดับ escape และ-nตัวเลือกที่จะไม่แสดงบรรทัดขึ้นบรรทัดใหม่ บางคนมีการ-Eปิดการใช้งานลำดับ escape บางส่วนมี-nแต่ไม่-eรายการลำดับการยกเว้นได้รับการสนับสนุนโดยechoการใช้งานอย่างใดอย่างหนึ่งไม่จำเป็นต้องเหมือนกับรายการอื่นที่สนับสนุน

สเวน Mascheck มีหน้าที่ดีที่แสดงให้เห็นถึงขอบเขตของปัญหา

ในบรรดาผู้echoใช้งานที่สนับสนุนตัวเลือกมีโดยทั่วไปการสนับสนุนของไม่มี--การทำเครื่องหมายจุดสิ้นสุดของตัวเลือก (เช่นechoในตัวของเปลือกหอยที่ไม่ใช่บอร์นเหมือนทำและ zsh สนับสนุน-สำหรับว่าที่) ดังนั้นสำหรับตัวอย่างเช่นมันเป็นเรื่องยากที่จะส่งออก"-n"ที่มีechoใน เปลือกหอยจำนวนมาก

บนเปลือกหอยบางอย่างเช่นbash¹หรือksh93²หรือyash( $ECHO_STYLEตัวแปร) พฤติกรรมแม้ขึ้นอยู่กับว่าเปลือกถูกรวบรวมหรือสิ่งแวดล้อม (GNU echoพฤติกรรมนอกจากนี้ยังจะมีการเปลี่ยนแปลงหาก$POSIXLY_CORRECTอยู่ในสภาพแวดล้อมและกับรุ่น4 , zsh's ด้วยbsd_echoตัวเลือก pdksh บางposixตัวมีตัวเลือกหรือไม่ว่าพวกเขาจะเรียกว่าเป็นshหรือไม่) ดังนั้นสองbash echos แม้จะมาจากเวอร์ชั่นเดียวกันbashก็ไม่รับประกันว่าจะทำงานเหมือนกัน

POSIX says: ถ้าอาร์กิวเมนต์แรกคือ-nหรือข้อโต้แย้งใด ๆ ที่มีเครื่องหมายแล้วพฤติกรรมที่ไม่ระบุรายละเอียด bashเสียงสะท้อนในเรื่องนั้นไม่ใช่ POSIX ในตัวอย่างecho -eนั้นไม่ได้เอาต์พุต-e<newline>ตามที่ POSIX ต้องการ ข้อมูลจำเพาะของ UNIX นั้นเข้มงวด-nและห้ามไม่ให้มีการขยายตัวของลำดับหนีบางอย่างรวมถึงลำดับที่\cจะหยุดการส่งออก

ข้อมูลจำเพาะเหล่านั้นไม่ได้มาเพื่อช่วยชีวิตที่นี่เนื่องจากการใช้งานหลายอย่างไม่สอดคล้อง แม้แต่ระบบที่ได้รับการรับรองบางอย่างเช่น macOS 5ก็ยังไม่เข้ากัน

ในการเป็นตัวแทนของความเป็นจริงในปัจจุบันPOSIX ควรพูดจริง ๆ ว่า : ถ้าอาร์กิวเมนต์แรกตรงกับ^-([eEn]*|-help|-version)$regexp ที่ขยายเพิ่มหรืออาร์กิวเมนต์ใด ๆ มีแบ็กสแลช (หรืออักขระที่มีการเข้ารหัสประกอบด้วยการเข้ารหัสอักขระแบ็กสแลชเหมือนαในโลแคล ยังไม่ระบุ

ทั้งหมดในที่ทุกท่านไม่ทราบว่าecho "$var"จะส่งออกจนกว่าคุณจะสามารถตรวจสอบว่าไม่ประกอบด้วยอักขระทับขวาและไม่ได้เริ่มต้นด้วย$var -ข้อมูลจำเพาะ POSIX จริง ๆ บอกให้เราใช้printfแทนในกรณีนั้น

ดังนั้นหมายความว่าคุณไม่สามารถใช้echoแสดงข้อมูลที่ไม่มีการควบคุมได้ กล่าวอีกนัยหนึ่งถ้าคุณกำลังเขียนสคริปต์และกำลังรับอินพุตภายนอก (จากผู้ใช้เป็นอาร์กิวเมนต์หรือชื่อไฟล์จากระบบไฟล์ ... ) คุณไม่สามารถใช้echoเพื่อแสดง

นี่โอเค:

echo >&2 Invalid file.

มันไม่ใช่:

echo >&2 "Invalid file: $file"

(แม้ว่ามันจะทำงานได้ดีกับการใช้งานบางอย่าง (ไม่สอดคล้องกับ UNIX) echoเช่นbashเมื่อxpg_echoตัวเลือกไม่ได้เปิดใช้งานไม่ทางใดก็ทางหนึ่งเช่นเวลาการรวบรวมหรือผ่านสภาพแวดล้อม)

file=$(echo "$var" | tr ' ' _)ไม่ได้ตกลงในการใช้งานมากที่สุด (ยกเว้นเป็นyashด้วยECHO_STYLE=raw(มีข้อแม้ที่ว่าyash's ตัวแปรไม่สามารถถือลำดับโดยพลการของไบต์ชื่อไฟล์จึงไม่พล) และzsh' s echo -E - "$var"6 )

printfบนมืออื่น ๆ ที่มีความน่าเชื่อถือมากขึ้นอย่างน้อยเมื่อมัน จำกัด echoอยู่ที่การใช้งานพื้นฐานของ

printf '%s\n' "$var"

จะส่งออกเนื้อหา$varตามด้วยอักขระขึ้นบรรทัดใหม่โดยไม่คำนึงถึงอักขระที่อาจมี

printf '%s' "$var"

จะเอาท์พุทมันโดยไม่ต้องขึ้นบรรทัดใหม่ของตัวละคร

ตอนนี้ก็มีความแตกต่างระหว่างprintfการใช้งาน มีคุณสมบัติหลักที่ระบุโดย POSIX แต่มีส่วนขยายจำนวนมาก ตัวอย่างเช่นบางสนับสนุนการ%qอ้างถึงข้อโต้แย้ง แต่วิธีการทำแตกต่างกันไปจากเปลือกหอยเพื่อเปลือกบางการสนับสนุน\uxxxxสำหรับอักขระ Unicode พฤติกรรมแตกต่างกันไปprintf '%10s\n' "$var"ในโลแคลหลายไบต์มีผลลัพธ์ที่แตกต่างกันอย่างน้อยสามรายการprintf %b '\123'

แต่ในที่สุดถ้าคุณยึดติดกับชุดคุณลักษณะ POSIX printfและอย่าพยายามทำอะไรที่แฟนซีเกินไปคุณก็จะไม่มีปัญหา

แต่โปรดจำไว้ว่าอาร์กิวเมนต์แรกคือรูปแบบดังนั้นจึงไม่ควรมีข้อมูลตัวแปร / ไม่มีการควบคุม

ความน่าเชื่อถือมากขึ้นechoสามารถดำเนินการโดยใช้printfเช่น:

echo() ( # subshell for local scope for $IFS
  IFS=" " # needed for "$*"
  printf '%s\n' "$*"
)

echo_n() (
  IFS=" "
  printf %s "$*"
)

echo_e() (
  IFS=" "
  printf '%b\n' "$*"
)

เชลล์ย่อย (ซึ่งหมายถึงการวางไข่กระบวนการพิเศษในการใช้งานเชลล์ส่วนใหญ่) สามารถหลีกเลี่ยงการใช้local IFSกับเชลล์จำนวนมากหรือโดยการเขียนเช่น:

echo() {
  if [ "$#" -gt 0 ]; then
     printf %s "$1"
     shift
  fi
  if [ "$#" -gt 0 ]; then
     printf ' %s' "$@"
  fi
  printf '\n'
}

หมายเหตุ

1. พฤติกรรมbashของวิธีechoการสามารถเปลี่ยนแปลงได้

ด้วยbashเวลาทำงานมีสองสิ่งที่ควบคุมพฤติกรรมของecho(ด้านข้างenable -n echoหรือนิยามใหม่echoเป็นฟังก์ชั่นหรือนามแฝง): xpg_echo bashตัวเลือกและไม่ว่าจะbashอยู่ในโหมด posix posixสามารถเปิดใช้งานโหมดได้หากbashถูกเรียกว่าเป็นshหรือPOSIXLY_CORRECTอยู่ในสภาพแวดล้อมหรือด้วยposixตัวเลือก:

พฤติกรรมเริ่มต้นในระบบส่วนใหญ่:

$ bash -c 'echo -n "\0101"'
\0101% # the % here denotes the absence of newline character

xpg_echo ขยายลำดับเมื่อ UNIX ต้องการ:

$ BASHOPTS=xpg_echo bash -c 'echo "\0101"'
A

มันยังคงให้เกียรติ-nและ-e(และ-E):

$ BASHOPTS=xpg_echo bash -c 'echo -n "\0101"'
A%

ด้วยxpg_echoและโหมด POSIX:

$ env BASHOPTS=xpg_echo POSIXLY_CORRECT=1 bash -c 'echo -n "\0101"'
-n A
$ env BASHOPTS=xpg_echo sh -c 'echo -n "\0101"' # (where sh is a symlink to bash)
-n A
$ env BASHOPTS=xpg_echo SHELLOPTS=posix bash -c 'echo -n "\0101"'
-n A

เวลานี้bashเป็นไปตาม POSIX และ UNIX โปรดทราบว่าในโหมด POSIX bashยังคงไม่สอดคล้องกับ POSIX เนื่องจากไม่ได้แสดงผล-eใน:

$ env SHELLOPTS=posix bash -c 'echo -e'

$

ค่าเริ่มต้นสำหรับ xpg_echo และ posix สามารถกำหนดได้ในเวลารวบรวมด้วยตัวเลือก--enable-xpg-echo-defaultและสคริปต์ นั่นเป็นสิ่งที่มักจะรุ่นล่าสุดของระบบปฏิบัติการ / X ทำเพื่อสร้างของพวกเขา ไม่มี Unix / Linux การดำเนินงาน / การจัดจำหน่ายในใจขวาของพวกเขาโดยทั่วไปจะทำว่าแม้ว่า ที่จริงแล้วไม่เป็นความจริงว่า Oracle มาพร้อมกับ Solaris 11 (ในแพ็คเกจเพิ่มเติม) ดูเหมือนว่าจะถูกสร้างขึ้นด้วย(ไม่ใช่ในกรณี Solaris 10)--enable-strict-posix-defaultconfigure/bin/sh/bin/bash/bin/bash--enable-xpg-echo-default

2. วิธีksh93's echoพฤติกรรมสามารถเปลี่ยนแปลงได้

ในksh93ไม่ว่าจะechoขยายลำดับการหลบหนีหรือไม่และตระหนักถึงตัวเลือกขึ้นอยู่กับเนื้อหาของ$PATHและ / หรือ$_AST_FEATURESตัวแปรสภาพแวดล้อม

หาก$PATHมีส่วนประกอบที่มี/5binหรือ/xpgก่อนหน้า/binหรือ/usr/binส่วนประกอบก็จะทำงานในลักษณะ SysV / UNIX (ขยายลำดับไม่ยอมรับตัวเลือก) หากพบ/ucbหรือ/bsdก่อนหรือถ้ามี$_AST_FEATURES7UNIVERSE = ucbก็จะทำงานในลักษณะ BSD 3 ( -eเพื่อเปิดใช้งานการขยายตัวรับรู้-n)

ค่าเริ่มต้นขึ้นอยู่กับระบบ BSD บน Debian (ดูผลลัพธ์builtin getconf; getconf UNIVERSEใน ksh93 รุ่นล่าสุด):

$ ksh93 -c 'echo -n' # default -> BSD (on Debian)
$ PATH=/foo/xpgbar:$PATH ksh93 -c 'echo -n' # /xpg before /bin or /usr/bin -> XPG
-n
$ PATH=/5binary:$PATH ksh93 -c 'echo -n' # /5bin before /bin or /usr/bin -> XPG
-n
$ PATH=/5binary:$PATH _AST_FEATURES='UNIVERSE = ucb' ksh93 -c 'echo -n' # -> BSD
$ PATH=/ucb:/foo/xpgbar:$PATH ksh93 -c 'echo -n' # /ucb first -> BSD
$ PATH=/bin:/foo/xpgbar:$PATH ksh93 -c 'echo -n' # /bin before /xpg -> default -> BSD

3. BSD สำหรับ echo -e?

การอ้างอิงถึง BSD สำหรับการจัดการ-eตัวเลือกนั้นทำให้เข้าใจผิดเล็กน้อยที่นี่ echoพฤติกรรมส่วนใหญ่ที่แตกต่างและเข้ากันไม่ได้ทั้งหมดถูกนำมาใช้ที่ AT&T:

  • \n, \0ooo, \cในการทำงานของโปรแกรมเมอร์บัลลังก์ยูนิกซ์ (Unix บนพื้นฐานของ V6) และส่วนที่เหลือ ( \b, \r... ) ในระบบยูนิกซ์ III Ref
  • -nใน Unix V7 (โดย Dennis Ritchie Ref )
  • -eใน Unix V8 (โดย Dennis Ritchie Ref )
  • -Eในตอนแรกอาจมาจากตัวเองbash(CWRU / CWRU.chlog ในเวอร์ชั่น 1.13.5กล่าวถึง Brian Fox เพิ่มใน 1992-10-18, GNU echoคัดลอกไม่นานหลังจากใน sh-utils-1.8 ออก 10 วันต่อมา)

ในขณะที่echobuiltin ของshหรือ BSDs ได้รับการสนับสนุน-eตั้งแต่วันที่พวกเขาเริ่มใช้ Almquist shell สำหรับมันในช่วงต้น 90s echoยูทิลิตี้แบบสแตนด์อโลนจนถึงทุกวันนี้ไม่สนับสนุนมัน ( FreeBSDechoยังไม่สนับสนุน-eแม้ว่ามันจะสนับสนุน-nเช่น Unix V7 (และ\cเฉพาะที่ท้ายอาร์กิวเมนต์สุดท้าย))

การจัดการของ-eถูกบันทึกอยู่ในksh93's echoเมื่ออยู่ใน BSD จักรวาลในรุ่น ksh93r ที่ปล่อยออกมาในปี 2006 และสามารถใช้งานได้ตลอดเวลารวบรวม

4. GNU echo เปลี่ยนแปลงพฤติกรรมใน 8.31

ตั้งแต่ coreutils 8.31 (และนี้กระทำ ) GNU echoตอนนี้ขยายลำดับหนีโดยค่าเริ่มต้นเมื่อ POSIXLY_CORRECT อยู่ในสภาพแวดล้อมเพื่อให้ตรงกับลักษณะการทำงานของbash -o posix -O xpg_echo's echobuiltin (ดูรายงานข้อผิดพลาด )

5. macOS echo

รุ่นส่วนใหญ่ของ MacOS ได้รับการรับรองจากยูนิกซ์ OpenGroup

shbuiltin ของพวกเขาechoเป็นไปตามที่มันเป็นbash(รุ่นเก่ามาก) สร้างด้วยการxpg_echoเปิดใช้งานโดยค่าเริ่มต้น แต่echoยูทิลิตี้แบบสแตนด์อโลนของพวกเขาไม่ได้ env echo -nเอาท์พุทอะไรแทน-n<newline>, env echo '\n'เอาท์พุทแทน\n<newline><newline><newline>

นั่น/bin/echoเป็นหนึ่งจาก FreeBSD ซึ่งยับยั้งการส่งออกขึ้นบรรทัดใหม่ถ้าอาร์กิวเมนต์แรกคือ-nหรือ (ตั้งแต่ปี 1995) ถ้าอาร์กิวเมนต์สุดท้ายจะสิ้นสุดลงใน\cแต่ไม่สนับสนุนลำดับทับขวาอื่น ๆ ที่จำเป็นโดย UNIX \\ไม่ได้

6. echoการใช้งานที่สามารถส่งออกข้อมูลทุกคำต่อคำ

พูดอย่างเคร่งครัดนอกจากนี้คุณยังสามารถนับว่า FreeBSD / MacOS /bin/echoเหนือ (ไม่ใช่เปลือกของพวกเขาechoในตัว) ที่zsh's echo -E - "$var"หรือyash' s ECHO_STYLE=raw echo "$var"( printf '%s\n' "$var") สามารถเขียน:

/bin/echo "$var
\c"

การใช้งานที่สนับสนุน-Eและ-n(หรือสามารถกำหนดค่าให้) สามารถทำได้เช่นกัน:

echo -nE "$var
"

และzsh's echo -nE - "$var"( printf %s "$var") สามารถเขียน

/bin/echo "$var\c"

7. _AST_FEATURESและ ASTUNIVERSE

_AST_FEATURESไม่ได้หมายถึงจะจัดการโดยตรงนั้นจะถูกใช้ในการเผยแพร่การตั้งค่า AST ข้ามเรียกคำสั่ง การกำหนดค่าหมายถึงการทำผ่านastgetconf()API (ไม่มีเอกสาร) ภายในksh93ที่getconfbuiltin (เปิดใช้งานด้วยbuiltin getconfหรือโดยการกล่าวอ้างcommand /opt/ast/bin/getconf) เป็นส่วนติดต่อกับastgetconf()

ตัวอย่างเช่นคุณต้องbuiltin getconf; getconf UNIVERSE = attเปลี่ยนการUNIVERSEตั้งค่าเป็นatt(ทำให้มีechoพฤติกรรมแบบ SysV เหนือสิ่งอื่นใด) หลังจากทำที่คุณจะสังเกตเห็นตัวแปรสภาพแวดล้อมมี$_AST_FEATURESUNIVERSE = att


13
การพัฒนายูนิกซ์ยุคแรกเกิดขึ้นมากมายและมีหลักการทางวิศวกรรมซอฟต์แวร์ที่ดีเช่น 'เมื่อคุณเปลี่ยนอินเทอร์เฟซเปลี่ยนชื่อ'ไม่ได้ใช้
Henk Langeveld

7
ข้อสังเกตข้อได้เปรียบหนึ่ง (และอาจจะเท่านั้น) ของการechoขยาย\xลำดับเมื่อเทียบกับเชลล์ซึ่งเป็นส่วนหนึ่งของไวยากรณ์ quoting คือคุณสามารถส่งออก NUL ไบต์ (อีกหนึ่งการออกแบบที่ผิดพลาดของ Unix นั้นเป็นตัวคั่นที่ไม่มีค่า สตริงที่ครึ่งหนึ่งของการเรียกระบบ (เช่นexecve()) ไม่สามารถใช้ลำดับไบต์แบบสุ่มได้
Stéphane Chazelas

อย่างที่คุณอาจเห็นในหน้าเว็บจาก Sven Maschek printfดูเหมือนว่าจะเป็นปัญหาเนื่องจากการใช้งานส่วนใหญ่ทำผิด เพียงปฏิบัติที่ถูกต้องฉันรู้อยู่ในboshหน้าจากสเวน Maschek ไม่แสดงรายการปัญหากับไบต์ null \0ผ่าน
schily

1
นี่เป็นคำตอบที่ดี - ขอบคุณ @ StéphaneChazelasที่เขียนมันขึ้นมา
JoshuaRLi

28

คุณอาจต้องการใช้printfสำหรับตัวเลือกการจัดรูปแบบ echoมีประโยชน์เมื่อมันมาถึงการพิมพ์ค่าของตัวแปรหรือบรรทัด (ง่าย) แต่นั่นคือทั้งหมดที่มีไป printfโดยทั่วไปสามารถทำสิ่งที่รุ่น C ของมันสามารถทำ

ตัวอย่างการใช้งานและความสามารถ:

Echo:

echo "*** Backup shell script ***"
echo
echo "Runtime: $(date) @ $(hostname)"
echo

printf:

vech="bike"
printf "%s\n" "$vech"

แหล่งที่มา:


@ 0xC0000022L ฉันยืนขอบคุณที่ถูกต้อง ฉันไม่ได้สังเกตเห็นว่าฉันเชื่อมโยงกับเว็บไซต์ที่ไม่ถูกต้องในการรีบเร่งเพื่อตอบคำถาม ขอบคุณสำหรับการสนับสนุนและการแก้ไขของคุณ
NlightNFotis

7
การใช้echoเพื่อพิมพ์ตัวแปรอาจล้มเหลวหากค่าของตัวแปรมีเมตาอักขระ
Keith Thompson

17

หนึ่ง "ความได้เปรียบ" ถ้าคุณต้องการที่จะเรียกมันว่าจะเป็นได้ว่าคุณจะได้ไม่ต้องบอกว่าชอบที่จะตีความลำดับหนีบางอย่างเช่นecho \nมันรู้ที่จะตีความพวกเขาและไม่จำเป็นต้อง-eทำ

printf "some\nmulti-lined\ntext\n"

(หมายเหตุ: \nจำเป็นต้องใช้ตัวสุดท้ายechoหมายความว่าเว้นแต่คุณจะให้-nตัวเลือก)

กับ

echo -e "some\nmulti-lined\ntext"

หมายเหตุสุดท้ายใน\n printfในตอนท้ายของวันที่มันเป็นเรื่องของรสนิยมและความต้องการสิ่งที่คุณใช้: หรือechoprintf


1
จริงสำหรับ/usr/bin/echoและbashตัวใน dash, kshและzshในตัวechoไม่จำเป็นต้องมี-eสวิทช์ที่จะขยายตัวอักษรทับขวาหนี
จัดการ

ทำไมคำพูดที่ทำให้ตกใจ? ข้อความของคุณบอกเป็นนัยว่าไม่จำเป็นต้องเป็นข้อได้เปรียบที่แท้จริง
Keith Thompson

2
@ KeithThompson: จริง ๆ แล้วสิ่งที่พวกเขาตั้งใจจะบอกคือไม่ใช่ทุกคนที่คิดว่ามันเป็นข้อได้เปรียบ
0xC0000022L

คุณช่วยขยายความหน่อยได้มั้ย? ทำไมถึงไม่ได้เปรียบ วลี "ถ้าคุณต้องการเรียกมันว่า" บอกเป็นนัย ๆ ว่าคุณคิดว่ามันไม่ใช่
Keith Thompson

2
printf '%s\n' 'foo\barหรือคุณก็สามารถทำได้
nyuszika7h

6

ข้อเสียเพียงอย่างเดียวของprintfประสิทธิภาพechoก็คือเชลล์ในตัวนั้นเร็วกว่ามาก สิ่งนี้เข้ามาเล่นโดยเฉพาะอย่างยิ่งใน Cygwin ซึ่งแต่ละอินสแตนซ์ของคำสั่งใหม่ทำให้เกิดโอเวอร์เฮดของ Windows อย่างหนัก เมื่อฉันเปลี่ยนโปรแกรม echo-heavy จากการใช้/bin/echoเป็นเสียงสะท้อนของเชลล์ประสิทธิภาพเพิ่มขึ้นเกือบสองเท่า มันเป็นการแลกเปลี่ยนระหว่างการพกพาและประสิทธิภาพ printfมันไม่ได้เป็นสแลมดังค์ที่จะใช้เสมอ


15
printfถูกสร้างขึ้นในหอยส่วนใหญ่ในปัจจุบัน (ทุบตี, ประ, ksh, zsh, yash, อนุพันธ์ pdksh บางส่วน ... ดังนั้นรวมถึงเปลือกหอยที่พบโดยทั่วไปใน cygwin เช่นกัน) ข้อยกเว้นที่น่าสังเกตเพียงอย่างเดียวคือpdkshอนุพันธ์บางประการ
Stéphane Chazelas

แต่การใช้งาน printf เหล่านั้นหลายแห่งนั้นใช้งานไม่ได้ นี่เป็นสิ่งสำคัญเมื่อคุณต้องการใช้printfเพื่อส่งออกไบต์ nul แต่การใช้งานบางอย่างตีความ `\ c 'ในรูปแบบสตริงแม้ว่าพวกเขาจะไม่ควร
Schily

2
@ schily พฤติกรรมของprintfไม่ได้ระบุไว้โดย POSIX หากคุณใช้\cในสตริงรูปแบบดังนั้นprintfการใช้งานสามารถทำสิ่งที่พวกเขาต้องการในเรื่องนั้น ตัวอย่างเช่นบางคนปฏิบัติต่อมันเหมือนใน PWB echo(ทำให้ printf ออก) ksh ใช้มันสำหรับ\cAอักขระควบคุม (สำหรับอาร์กิวเมนต์รูปแบบ printf และ$'...'ไม่ใช่สำหรับechoหรือprint! ไม่แน่ใจว่าสิ่งที่จะทำอย่างไรกับการพิมพ์ไบต์ NUL หรือบางทีคุณอาจจะหมายถึงksh's printf '\c@'?
Stéphane Chazelas
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.