ระงับการติดตามการเรียกใช้งานสำหรับคำสั่ง echo หรือไม่


29

ฉันทำงานเชลล์สคริปต์จากเจนกินส์ซึ่ง kicks #!/bin/sh -exปิดเชลล์สคริปต์ที่มีตัวเลือก

ตามBash Shebang สำหรับหุ่น? ,, -x"ทำให้เชลล์พิมพ์การติดตามการดำเนินการ" ซึ่งดีมากสำหรับวัตถุประสงค์ส่วนใหญ่ - ยกเว้น echos:

echo "Message"

ผลิตผลลัพธ์

+ echo "Message"
Message

ซึ่งค่อนข้างซ้ำซ้อนและดูแปลกไปหน่อย มีวิธีที่จะ-xเปิดใช้งาน แต่มีเฉพาะเอาต์พุต

Message

แทนที่จะเป็นสองบรรทัดด้านบนเช่นโดยนำหน้าคำสั่ง echo ด้วยอักขระคำสั่งพิเศษหรือเปลี่ยนเส้นทางเอาต์พุต

คำตอบ:


20

เมื่อคุณขึ้นไปถึงคอใน alligators มันง่ายที่จะลืมว่าเป้าหมายคือการระบายหนอง                   - คำพูดยอดนิยม

คำถามเกี่ยวกับ echoและยังมีคำตอบส่วนใหญ่ที่มุ่งเน้นไปที่วิธีการแอบset +xสั่งให้มีวิธีแก้ปัญหาที่ง่ายกว่าและตรงกว่า:

{ echo "Message"; } 2> /dev/null

(ฉันยอมรับว่าฉันอาจไม่ได้คิด{ …; } 2> /dev/null ว่าฉันไม่ได้เห็นคำตอบก่อนหน้านี้หรือไม่)

มันค่อนข้างยุ่งยาก แต่ถ้าคุณมีบล็อกติดต่อกัน echoคำสั่งคุณไม่จำเป็นต้องทำทีละคำ:

{
  echo "The quick brown fox"
  echo "jumps over the lazy dog."
} 2> /dev/null

โปรดทราบว่าคุณไม่จำเป็นต้องใช้เครื่องหมายอัฒภาคเมื่อคุณมีการขึ้นบรรทัดใหม่

คุณสามารถลดภาระการพิมพ์โดยใช้แนวคิดของ kenorb ใน การเปิด/dev/nullอย่างถาวรบนตัวอธิบายไฟล์ที่ไม่ได้มาตรฐาน (เช่น 3) จากนั้นพูด2>&3แทน2> /dev/nullตลอดเวลา


สี่คำตอบแรกในขณะที่เขียนนี้ต้องทำอะไรเป็นพิเศษ (และในกรณีส่วนใหญ่ยุ่งยาก) ทุกechoครั้งที่คุณทำ หากคุณต้องการให้ทุก echoคำสั่งระงับการติดตามการเรียกใช้งาน (และทำไมคุณไม่ลองใช้) คุณสามารถทำได้ทั่วโลกโดยไม่ต้องใส่รหัสจำนวนมาก ก่อนอื่นฉันสังเกตว่านามแฝงไม่ได้ติดตาม:

$ myfunc()
> {
>     date
> }
$ alias myalias="date"
$ set -x
$ date
+ date
Mon, Oct 31, 2016  0:00:00 AM           # Happy Halloween!
$ myfunc
+ myfunc                                # Note that function call is traced.
+ date
Mon, Oct 31, 2016  0:00:01 AM
$ myalias
+ date                                  # Note that it doesn’t say  + myalias
Mon, Oct 31, 2016  0:00:02 AM

(โปรดทราบว่าตัวอย่างของสคริปต์ต่อไปนี้จะทำงานถ้า Shebang คือ#!/bin/shแม้ว่า/bin/shจะเป็นลิงก์ไปยัง bash แต่ถ้าเป็น Shebang #!/bin/bashคุณต้องเพิ่มshopt -s expand_aliasesคำสั่งเพื่อให้ aliases ทำงานในสคริปต์)

ดังนั้นสำหรับเคล็ดลับแรกของฉัน:

alias echo='{ set +x; } 2> /dev/null; builtin echo'

ตอนนี้เมื่อเราพูดว่าecho "Message"เรากำลังเรียกนามแฝงซึ่งไม่ได้ติดตาม นามแฝงจะปิดตัวเลือกการติดตามในขณะที่ระงับข้อความการติดตามจากsetคำสั่ง (ใช้เทคนิคที่แสดงครั้งแรกในคำตอบของผู้ใช้ 5071535 ) แล้วดำเนินการechoคำสั่งจริง สิ่งนี้ทำให้เราได้ผลคล้ายกับคำตอบของผู้ใช้ 5071535 โดยไม่จำเป็นต้องแก้ไขโค้ดในทุก echoคำสั่ง อย่างไรก็ตามโหมดนี้จะปิดโหมดการติดตาม เราไม่สามารถใส่ a set -xalias (หรืออย่างน้อยก็ไม่ง่าย) เพราะ alias อนุญาตให้ใช้สตริงแทนคำได้ ไม่มีส่วนของสตริงนามแฝงใด ๆ ที่สามารถถูกฉีดเข้าไปในคำสั่ง หลังจากอาร์กิวเมนต์ (เช่น, "Message") ตัวอย่างเช่นหากสคริปต์มี

date
echo "The quick brown fox"
echo "jumps over the lazy dog."
date

ผลลัพธ์จะเป็น

+ date
Mon, Oct 31, 2016  0:00:03 AM
The quick brown fox
jumps over the lazy dog.
Mon, Oct 31, 2016  0:00:04 AM           # Note that it doesn’t say  + date

ดังนั้นคุณยังต้องเปิดใช้งานตัวเลือกการติดตามอีกครั้งหลังจากแสดงข้อความ - แต่เพียงครั้งเดียวหลังจากบล็อกechoคำสั่งต่อเนื่องทุกบล็อก :

date
echo "The quick brown fox"
echo "jumps over the lazy dog."
set -x
date


มันจะดีถ้าเราสามารถสร้างset -xอัตโนมัติหลังจากecho- และเราทำได้โดยใช้กลอุบายเพิ่มเติม แต่ก่อนที่ฉันจะนำเสนอให้พิจารณาสิ่งนี้ OP เริ่มต้นด้วยสคริปต์ที่ใช้#!/bin/sh -exShebang ผู้ใช้สามารถลบออกxจาก shebang โดยปริยายและมีสคริปต์ที่ทำงานได้ตามปกติโดยไม่ต้องมีการติดตามการเรียกใช้งาน มันจะดีถ้าเราสามารถพัฒนาวิธีแก้ปัญหาที่รักษาคุณสมบัตินั้นไว้ คำตอบแรก ๆ ที่นี่ล้มเหลวเนื่องจากคุณสมบัตินั้นเปิดใช้งานการติดตาม“ ย้อนกลับ” หลังจากechoคำสั่งโดยไม่มีเงื่อนไขโดยไม่คำนึงว่ามันเปิดอยู่แล้วหรือไม่  คำตอบนี้อย่างเด่นชัดล้มเหลวในการรับรู้ปัญหาที่มันเข้ามาแทนที่ echoเอาต์พุตพร้อมเอาต์พุตการติดตาม ดังนั้นข้อความทั้งหมดจะหายไปหากการติดตามถูกปิด ตอนนี้ฉันจะนำเสนอทางออกที่เปิดการสืบค้นกลับหลังจากechoคำสั่งแบบมีเงื่อนไข - เฉพาะเมื่อเปิดใช้แล้ว การลดระดับเป็นโซลูชันที่เปลี่ยนการติดตาม“ ย้อนกลับ” โดยไม่มีเงื่อนไขนั้นเป็นเรื่องเล็กน้อยและถูกทิ้งไว้เป็นแบบฝึกหัด

alias echo='{ save_flags="$-"; set +x;} 2> /dev/null; echo_and_restore'
echo_and_restore() {
        builtin echo "$*"
        case "$save_flags" in
         (*x*)  set -x
        esac
}

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

คุณสามารถแทรกเจ็ดบรรทัดข้างต้น (แปดถ้าคุณมีshopt) ที่จุดเริ่มต้นของสคริปต์และปล่อยให้ส่วนที่เหลืออยู่คนเดียว

สิ่งนี้จะช่วยให้คุณ

  1. เพื่อใช้บรรทัด shebang ต่อไปนี้:
    #! / bin / sh -ex
    #! / bin / sh -e
    #! / bin / sh –x
    หรือเพียงแค่ธรรมดา
    #! / bin / ดวลจุดโทษ
    และควรทำงานตามที่คาดไว้
  2. มีรหัสเช่น
    (shebang) 
    คำสั่ง1
    คำสั่ง2
    คำสั่ง3
    ชุด -x
    คำสั่ง4
    คำสั่ง5
    คำสั่ง6
    ชุด + x
    คำสั่ง7
    คำสั่ง8
    คำสั่ง9
    และ
    • คำสั่ง 4, 5 และ 6 จะถูกติดตาม - เว้นแต่ว่าหนึ่งในนั้นคือechoในกรณีนี้จะถูกดำเนินการ แต่ไม่ได้ติดตาม (แม้ว่าคำสั่ง 5 จะเป็นechoคำสั่ง 6 จะยังคงติดตามอยู่)
    • คำสั่ง 7, 8 และ 9 จะไม่ถูกติดตาม แม้ว่าคำสั่ง 8 จะเป็นechoคำสั่ง 9 ยังคงไม่ถูกติดตาม
    • คำสั่งที่ 1, 2 และ 3 จะได้รับการตรวจสอบ (เช่น 4, 5 และ 6) หรือไม่ (เช่น 7, 8 และ 9) ขึ้นอยู่กับว่า shebang xรวมถึง

ป.ล. ฉันค้นพบว่าในระบบของฉันฉันสามารถทิ้งbuiltinคำหลักไว้ในคำตอบตรงกลาง (อันที่เป็นเพียงนามแฝงecho) ไม่น่าแปลกใจเลย bash (1) บอกว่าระหว่างการขยายนามแฝง ...

... คำที่เหมือนกับนามแฝงที่กำลังขยายจะไม่ถูกขยายอีกเป็นครั้งที่สอง ซึ่งหมายความว่าที่หนึ่งอาจนามแฝงlsไปls -Fเช่นทุบตีและไม่พยายามที่จะขยายซ้ำข้อความทดแทน

ไม่น่าแปลกใจมากเกินไปคำตอบสุดท้าย (หนึ่งด้วยecho_and_restore) ล้มเหลวหากbuiltinคำหลักที่ถูกละ1 แต่แปลกที่มันทำงานถ้าฉันลบbuiltinและเปลี่ยนคำสั่ง:

echo_and_restore() {
        echo "$*"
        case "$save_flags" in
         (*x*)  set -x
        esac
}
alias echo='{ save_flags="$-"; set +x;} 2> /dev/null; echo_and_restore'

__________
1  ดูเหมือนจะทำให้เกิดพฤติกรรมที่ไม่ได้กำหนด ฉันเคยเห็น

  • วงวนไม่สิ้นสุด (อาจเป็นเพราะการเรียกซ้ำแบบไม่ จำกัด )
  • /dev/null: Bad addressข้อผิดพลาดและ
  • การถ่ายโอนข้อมูลหลัก

2
ฉันได้เห็นเทคนิคมายากลที่น่าอัศจรรย์บางอย่างที่ทำกับนามแฝงดังนั้นฉันรู้ว่าความรู้ของฉันนั้นไม่สมบูรณ์ หากใครสามารถนำเสนอวิธีการทำเทียบเท่าecho +x; echo "$*"; echo -xในนามแฝงฉันต้องการที่จะเห็นมัน
G-Man พูดว่า 'Reinstate Monica'

11

ฉันพบวิธีแก้ปัญหาบางส่วนที่InformIT :

#!/bin/bash -ex
set +x; 
echo "shell tracing is disabled here"; set -x;
echo "but is enabled here"

เอาท์พุท

set +x; 
shell tracing is disabled here 
+ echo "but is enabled here"
but is enabled here

น่าเสียดายที่เสียงสะท้อนยังคงอยู่set +xแต่อย่างน้อยก็เงียบหลังจากนั้น อย่างน้อยก็เป็นวิธีแก้ปัญหาบางส่วน

แต่อาจมีวิธีที่ดีกว่าในการทำเช่นนี้? :)


2

วิธีนี้จะปรับปรุงวิธีการแก้ปัญหาของคุณเองโดยกำจัดset +xผลลัพธ์:

#!/bin/bash -ex
{ set +x; } 2>/dev/null
echo "shell tracing is disabled here"; set -x;
echo "but is enabled here"

2

ใส่set +xในวงเล็บดังนั้นมันจะใช้สำหรับขอบเขตภายในเท่านั้น

ตัวอย่างเช่น:

#!/bin/bash -x
exec 3<> /dev/null
(echo foo1 $(set +x)) 2>&3
($(set +x) echo foo2) 2>&3
( set +x; echo foo3 ) 2>&3
true

จะส่งออก:

$ ./foo.sh 
+ exec
foo1
foo2
foo3
+ true

แก้ไขฉันถ้าฉันผิด แต่ฉันไม่คิดว่าset +xภายใน subshell (หรือการใช้ subshells เลย) ทำสิ่งที่มีประโยชน์ คุณสามารถลบออกและรับผลลัพธ์เดียวกัน มันคือ stderr ที่เปลี่ยนเส้นทางไปยัง / dev / null ที่กำลังทำงานของการติดตาม "ปิดใช้งาน" ชั่วคราว ... ดูเหมือนว่าecho foo1 2>/dev/nullฯลฯ จะมีประสิทธิภาพและอ่านได้มากขึ้น
Tyler Rick

การติดตามสคริปต์ของคุณอาจส่งผลต่อประสิทธิภาพ การเปลี่ยนเส้นทางที่สอง & 2 เป็น NULL อาจไม่เหมือนกันเมื่อคุณคาดหวังข้อผิดพลาดอื่น ๆ
kenorb

แก้ไขให้ฉันถ้าฉันผิด แต่ในตัวอย่างของคุณคุณได้เปิดใช้งานการติดตามในสคริปต์ของคุณ (ด้วยbash -x) แล้วและคุณเปลี่ยนเส้นทาง&2ไปเป็นโมฆะแล้ว (เนื่องจาก&3ถูกเปลี่ยนเส้นทางไปเป็นโมฆะ) ดังนั้นฉันไม่แน่ใจว่า บางทีเราอาจต้องการตัวอย่างที่ดีกว่าซึ่งแสดงให้เห็นถึงจุดของคุณ แต่ในตัวอย่างที่กำหนดอย่างน้อยมันก็ดูเหมือนว่ามันจะง่ายขึ้นโดยไม่สูญเสียผลประโยชน์ใด ๆ
Tyler Rick

1

ฉันชอบคำตอบที่ครอบคลุมและอธิบายอย่างดีโดย g-manและพิจารณาว่าเป็นคำตอบที่ดีที่สุดที่ให้ไว้ มันสนใจเกี่ยวกับบริบทของสคริปต์และไม่บังคับการกำหนดค่าเมื่อไม่ต้องการ ดังนั้นหากคุณกำลังอ่านคำตอบนี้ก่อนอื่นให้ตรวจสอบว่ามีคุณความดีทั้งหมดอยู่ที่นั่น

อย่างไรก็ตามในคำตอบนั้นมีชิ้นส่วนสำคัญที่ขาดหายไป: วิธีการที่เสนอไม่สามารถใช้ได้กับกรณีการใช้งานทั่วไปเช่นข้อผิดพลาดในการรายงาน

COMMAND || echo "Command failed!"

เนื่องจากวิธีสร้างนามแฝงสิ่งนี้จะขยายเป็น

COMMAND || { save_flags="$-"; set +x; } 2>/dev/null; echo_and_restore "Command failed!"

และคุณเดาได้ว่าecho_and_restoreจะถูกประหารชีวิตเสมอโดยไม่มีเงื่อนไข เนื่องจากชิ้นset +xส่วนไม่ทำงานหมายความว่าเนื้อหาของฟังก์ชั่นนั้นจะถูกพิมพ์เช่นกัน

การเปลี่ยนผ่านมา;เพื่อ&&จะไม่ทำงานอย่างใดอย่างหนึ่งเพราะในทุบตี||และ&&มีซ้ายเชื่อมโยง

ฉันพบการดัดแปลงที่ใช้งานได้กับกรณีการใช้งานนี้:

echo_and_restore() {
    echo "$(cat -)"
    case "$save_flags" in
        (*x*) set -x
    esac
}
alias echo='({ save_flags="$-"; set +x; } 2>/dev/null; echo_and_restore) <<<'

มันใช้ subshell (คน(...)บางส่วน) ในการสั่งซื้อไปยังกลุ่มคำสั่งทั้งหมดแล้วผ่านสายป้อนผ่านstdinเป็นนี่ String (คน<<<สิ่ง) cat -ซึ่งจะมีการพิมพ์แล้วโดย -เป็นตัวเลือก แต่คุณรู้ว่า " อย่างชัดเจนจะดีกว่าโดยปริยาย "

คุณสามารถใช้cat -โดยตรงโดยไม่ต้องก้องแต่ฉันชอบวิธีนี้เพราะมันช่วยให้ฉันสามารถเพิ่มสายอื่น ๆ เพื่อเอาท์พุท ตัวอย่างเช่นฉันมักจะใช้มันเช่นนี้

BASENAME="$(basename "$0")"  # Complete file name
...
echo "[${BASENAME}] $(cat -)"

และตอนนี้มันทำงานได้อย่างสวยงาม:

false || echo "Command failed"
> [test.sh] Command failed

0

การดำเนินการสืบค้นกลับไปที่stderrกรองด้วยวิธีนี้:

./script.sh 2> >(grep -v "^+ echo " >&2)

คำอธิบายบางอย่างทีละขั้นตอน:

  • stderr ถูกเปลี่ยนเส้นทาง ... - 2>
  • ... กับคำสั่ง ->(…)
  • grep คือคำสั่ง ...
  • ... ซึ่งต้องการจุดเริ่มต้นของบรรทัด ... - ^
  • ... ตามด้วย+ echo...
  • …จากนั้นกลับgrepการแข่งขัน… --v
  • ... และทิ้งทุกบรรทัดที่คุณไม่ต้องการ
  • ผลจะไปตามปกติstdout; เราเปลี่ยนเส้นทางไปยังstderrที่ที่มันอยู่ ->&2

ปัญหาคือ (ฉันเดา) โซลูชันนี้อาจยกเลิกการซิงโครไนซ์สตรีม เนื่องจากการกรองstderrอาจมีความล่าช้าเล็กน้อยstdout(ซึ่งechoผลลัพธ์เป็นของค่าเริ่มต้น) ในการแก้ไขปัญหาคุณสามารถเข้าร่วมสตรีมก่อนถ้าคุณไม่สนใจทั้งสองสิ่งในstdout:

./script.sh > >(grep -v "^+ echo ") 2>&1

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

รหัสมีลักษณะดังนี้:

#!/bin/bash -x

{
 # original script here
 # …
} 2> >(grep -v "^+ echo " >&2)

เรียกใช้โดยไม่มีลูกเล่น:

./script.sh

อีกครั้งใช้> >(grep -v "^+ echo ") 2>&1เพื่อรักษาข้อมูลให้ตรงกันที่ค่าใช้จ่ายในการเข้าร่วมกระแส


อีกแนวทางหนึ่ง คุณจะได้รับ "ซ้ำซ้อนบิต" และเอาท์พุแปลกเพราะผสม terminal ของคุณstdoutstderrและ ลำธารทั้งสองนี้เป็นสัตว์ต่างกันด้วยเหตุผล ตรวจสอบว่าการวิเคราะห์stderrนั้นเหมาะกับความต้องการของคุณหรือไม่ ทิ้งstdout:

./script.sh > /dev/null

หากคุณมีข้อความในechoการดีบัก / ข้อผิดพลาดการพิมพ์ในสคริปต์stderrคุณอาจกำจัดความซ้ำซ้อนในวิธีที่อธิบายไว้ข้างต้น คำสั่งแบบเต็ม:

./script.sh > /dev/null 2> >(grep -v "^+ echo " >&2)

ครั้งนี้เราทำงานด้วยstderrเท่านั้นดังนั้นการซิงโครไนซ์จะไม่เป็นข้อกังวลอีกต่อไป น่าเสียดายที่วิธีนี้คุณจะไม่เห็นร่องรอยหรือเอาท์พุทของechoภาพนั้นไปยังstdout(ถ้ามี) เราได้พยายามที่จะสร้างตัวกรองของเราในการตรวจสอบการเปลี่ยนเส้นทาง ( >&2) แต่ถ้าคุณมองไปที่echo foobar >&2, echo >&2 foobarและecho "foobar >&2"แล้วคุณอาจจะเห็นว่าสิ่งที่ได้รับความซับซ้อน

มากขึ้นอยู่กับ echos ที่คุณมีในสคริปต์ของคุณ คิดสองครั้งก่อนที่คุณจะใช้ตัวกรองที่ซับซ้อนบางอย่างมันอาจย้อนกลับมา มันเป็นการดีที่จะมีความซ้ำซ้อนมากกว่าที่จะพลาดข้อมูลสำคัญบางอย่างโดยไม่ตั้งใจ


แทนที่จะทิ้งร่องรอยการดำเนินการของechoเราสามารถละทิ้งเอาต์พุต - และเอาต์พุตใด ๆ ยกเว้นการติดตาม หากต้องการวิเคราะห์ร่องรอยการดำเนินการให้ลอง:

./script.sh > /dev/null 2> >(grep "^+ " >&2)

จะเข้าใจผิด? ไม่คิดว่าจะเกิดอะไรขึ้นหากมีecho "+ rm -rf --no-preserve-root /" >&2สคริปต์ บางคนอาจมีอาการหัวใจวาย


และในที่สุดก็…

โชคดีที่มีBASH_XTRACEFDตัวแปรด้านสิ่งแวดล้อม จากman bash:

BASH_XTRACEFD
หากตั้งค่าเป็นจำนวนเต็มที่สอดคล้องกับ file descriptor ที่ถูกต้อง bash จะเขียนเอาต์พุตการติดตามที่สร้างขึ้นเมื่อset -xเปิดใช้งานกับ descriptor ไฟล์นั้น

เราสามารถใช้สิ่งนี้:

(exec 3>trace.txt; BASH_XTRACEFD=3 ./script.sh)
less trace.txt

หมายเหตุบรรทัดแรกวางไข่เชลล์ย่อย วิธีนี้ file descriptor จะไม่ถูกต้องหรือตัวแปรที่กำหนดในเชลล์ปัจจุบันหลังจากนั้น

ขอบคุณที่BASH_XTRACEFDคุณสามารถวิเคราะห์ร่องรอยที่ไม่มี echos และเอาท์พุตอื่น ๆ ไม่ว่ามันจะเป็นอะไรก็ตาม มันไม่ได้เป็นอย่างที่คุณต้องการ แต่การวิเคราะห์ของฉันทำให้ฉันคิดว่านี่คือ (โดยทั่วไป) วิธีที่ถูกต้อง

แน่นอนคุณสามารถใช้วิธีอื่นโดยเฉพาะอย่างยิ่งเมื่อคุณต้องการวิเคราะห์stdoutและ / หรือstderrพร้อมกับร่องรอยของคุณ คุณเพียงแค่ต้องจำไว้ว่ามีข้อ จำกัด และข้อผิดพลาดบางอย่าง ฉันพยายามที่จะแสดง (บางส่วน) พวกเขา


0

ใน Makefile คุณสามารถใช้@สัญลักษณ์

ตัวอย่างการใช้งาน: @echo 'message'

จากเอกสาร GNU นี้ :

เมื่อบรรทัดเริ่มต้นด้วย '@' การสะท้อนของบรรทัดนั้นจะถูกระงับ เครื่องหมาย '@' ถูกยกเลิกก่อนที่บรรทัดจะถูกส่งไปยังเชลล์ โดยทั่วไปคุณจะใช้สิ่งนี้สำหรับคำสั่งที่มีเอฟเฟกต์เพียงอย่างเดียวคือการพิมพ์บางอย่างเช่นคำสั่ง echo เพื่อระบุความคืบหน้าผ่าน makefile


สวัสดีเอกสารที่คุณอ้างอิงมีไว้สำหรับ gnu make ไม่ใช่ shell คุณแน่ใจเหรอ ฉันพบข้อผิดพลาด./test.sh: line 1: @echo: command not foundแต่ฉันกำลังใช้ bash

ว้าวขอโทษด้วยที่ฉันอ่านผิดไปหมด ใช่@ใช้งานได้เฉพาะเมื่อคุณสะท้อนใน makefiles
ดีเร็ก

@derek ฉันได้แก้ไขคำตอบดั้งเดิมของคุณดังนั้นตอนนี้มันชัดเจนว่าโซลูชันมี จำกัด สำหรับ Makefiles เท่านั้น ฉันกำลังมองหาอันนี้จริง ๆ แล้วฉันต้องการความคิดเห็นของคุณไม่ให้มีชื่อเสียงเชิงลบ หวังว่าผู้คนจะได้รับประโยชน์เช่นกัน
Shakaron

-1

แก้ไขเมื่อ 29 ต.ค. 2559 ตามคำแนะนำของผู้ดำเนินรายการว่าต้นฉบับไม่มีข้อมูลเพียงพอที่จะเข้าใจว่าเกิดอะไรขึ้น

"เคล็ดลับ" นี้สร้างเอาต์พุตข้อความหนึ่งบรรทัดที่เทอร์มินัลเมื่อ xtrace แอ็คทีฟ:

คำถามเดิมคือมีวิธีที่จะออกจาก -x เปิดใช้งาน แต่เพียงการส่งออกข้อความแทนของทั้งสองสาย นี่เป็นคำพูดที่ถูกต้องจากคำถาม

ฉันเข้าใจคำถามว่าจะเป็นอย่างไร "ปล่อยให้ set -x เปิดใช้งานและสร้างบรรทัดเดียวสำหรับข้อความ"?

  • ในความหมายทั่วโลกคำถามนี้โดยทั่วไปเกี่ยวกับสุนทรียภาพ - ผู้ถามต้องการสร้างบรรทัดเดียวแทนที่จะเป็นสองบรรทัดที่ซ้ำกันจริง ๆ ที่ผลิตในขณะที่ xtrace ทำงานอยู่

ดังนั้นโดยสรุป OP ต้องการ:

  1. หากต้องการตั้งค่า -x ให้มีผล
  2. ผลิตข้อความที่มนุษย์อ่านได้
  3. สร้างเอาต์พุตข้อความบรรทัดเดียวเท่านั้น

OP ไม่ต้องการให้ใช้คำสั่งecho พวกเขาอ้างว่าเป็นตัวอย่างของการผลิตข้อความโดยใช้ตัวย่อเช่นซึ่งย่อมาจากละติน exempli gratia หรือ "ตัวอย่าง"

เมื่อคิดถึง "นอกกรอบ" และละทิ้งการใช้เสียงสะท้อนเพื่อสร้างข้อความฉันทราบว่าคำสั่งการมอบหมายสามารถตอบสนองความต้องการทั้งหมดได้

ทำการกำหนดสตริงข้อความ (ที่มีข้อความ) ให้กับตัวแปรที่ไม่แอ็คทีฟ

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

echo="====================== Divider line ================="

สิ่งที่คุณจะเห็นบนเทอร์มินัลมีเพียง 1 บรรทัด:

++ echo='====================== Divider line ================='

ไม่ใช่สองเนื่องจาก OP ไม่ชอบ:

+ echo '====================== Divider line ================='
====================== Divider line =================

นี่คือตัวอย่างสคริปต์ที่จะสาธิต โปรดทราบว่าการทดแทนตัวแปรในข้อความ ($ ไดเรกทอรีไดเรกทอรีชื่อ 4 บรรทัดจากจุดสิ้นสุด) ทำงานดังนั้นคุณสามารถติดตามตัวแปรโดยใช้วิธีนี้

#!/bin/bash -exu
#
#  Example Script showing how, with trace active, messages can be produced
#  without producing two virtually duplicate line on the terminal as echo does.
#
dummy="====================== Entering Test Script ================="
if [[ $PWD == $HOME ]];  then
  dummy="*** "
  dummy="*** Working in home directory!"
  dummy="*** "
  ls -la *.c || :
else
  dummy="---- C Files in current directory"
  ls -la *.c || :
  dummy="----. C Files in Home directory "$HOME
  ls -la  $HOME/*.c || :
fi

และนี่คือผลลัพธ์จากการรันในรูทจากนั้นโฮมไดเร็กตอรี่

$ cd /&&DemoScript
+ dummy='====================== Entering Test Script ================='
+ [[ / == /g/GNU-GCC/home/user ]]
+ dummy='---- C Files in current directory'
+ ls -la '*.c'
ls: *.c: No such file or directory
+ :
+ dummy='----. C Files in Home directory /g/GNU-GCC/home/user'
+ ls -la /g/GNU-GCC/home/user/HelloWorld.c /g/GNU-GCC/home/user/hw.c
-rw-r--r-- 1 user Administrators 73 Oct 10 22:21 /g/GNU-GCC/home/user/HelloWorld.c
-rw-r--r-- 1 user Administrators 73 Oct 10 22:21 /g/GNU-GCC/home/user/hw.c
+ dummy=---------------------------------

$ cd ~&&DemoScript
+ dummy='====================== Entering Test Script ================='
+ [[ /g/GNU-GCC/home/user == /g/GNU-GCC/home/user ]]
+ dummy='*** '
+ dummy='*** Working in home directory!'
+ dummy='*** '
+ ls -la HelloWorld.c hw.c
-rw-r--r-- 1 user Administrators 73 Oct 10 22:21 HelloWorld.c
-rw-r--r-- 1 user Administrators 73 Oct 10 22:21 hw.c
+ dummy=---------------------------------

1
หมายเหตุแม้คำตอบที่ถูกลบแล้วของคุณ (ซึ่งเป็นสำเนา) ก็ยังไม่ตอบคำถามเนื่องจากคำตอบไม่ได้ส่งออกเฉพาะข้อความที่ไม่มีคำสั่ง echo ที่เกี่ยวข้องซึ่งเป็นสิ่งที่ OP ร้องขอ
DavidPostill


@ David ฉันได้ขยายคำอธิบายต่อความคิดเห็นในฟอรัม meta
HiTechHiTouch

@ David อีกครั้งฉันขอแนะนำให้คุณอ่าน OP อย่างระมัดระวังให้ความสนใจกับละติน ".eg" ผู้โพสต์ไม่จำเป็นต้องใช้คำสั่ง echo OP อ้างอิงเพียงเสียงสะท้อนเป็นตัวอย่าง (พร้อมกับการเปลี่ยนเส้นทาง) ของวิธีการที่เป็นไปได้ในการแก้ปัญหา ปรากฎว่าคุณไม่ต้องการเช่นกัน
HiTechHiTouch

และสิ่งที่ถ้า OP ต้องการที่จะทำสิ่งที่ชอบecho "Here are the files in this directory:" *?
G-Man กล่าวว่า 'Reinstate Monica'
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.