วิธี cat << EOF >> ไฟล์ที่มีรหัส?


108

ฉันต้องการพิมพ์รหัสลงในไฟล์โดยใช้cat <<EOF >>:

cat <<EOF >> brightup.sh
!/bin/bash
curr=`cat /sys/class/backlight/intel_backlight/actual_brightness`
if [ $curr -lt 4477 ]; then
   curr=$((curr+406));
   echo $curr  > /sys/class/backlight/intel_backlight/brightness;
fi
EOF

แต่เมื่อฉันตรวจสอบผลลัพธ์ของไฟล์ฉันจะได้รับสิ่งนี้:

!/bin/bash
curr=1634
if [  -lt 4477 ]; then
   curr=406;
   echo   > /sys/class/backlight/intel_backlight/brightness;
fi

ฉันพยายามใส่เครื่องหมายคำพูดเดี่ยว แต่ผลลัพธ์ก็มีเครื่องหมายคำพูดเดี่ยวด้วย ฉันจะหลีกเลี่ยงปัญหานี้ได้อย่างไร


2
คุณควรแก้ไข shebang ด้วย บรรทัดแรกจะต้องเป็นตัวอักษร#!/bin/bashและไม่มีอะไรอื่น - #!คือสิ่งที่ทำให้มันเป็นบรรทัด Shebang ที่ถูกต้องและสิ่งที่ตามมาคือเส้นทางไปยังล่าม
tripleee

1
ดูและค้นหาman bash Here Documentsรายละเอียดทั้งหมดที่นั่น
Hong

1
ในขณะที่มาช้าไวยากรณ์สมัยใหม่สำหรับการทดแทนกระบวนการจึงถูก$(command)แทนที่`command`ด้วย สำหรับการรับเนื้อหาของไฟล์ Bash มี$(<file)
tripleee

คำตอบ:


169

คุณต้องการการเปลี่ยนแปลงเพียงเล็กน้อย <<อ้างเดียวตัวคั่นที่นี่เอกสารหลัง

cat <<'EOF' >> brightup.sh

หรือแบ็กสแลชที่เทียบเท่ากัน - หนีมัน:

cat <<\EOF >>brightup.sh

หากไม่มีการอ้างถึงเอกสารที่นี่จะได้รับการแทนที่ตัวแปร backticks จะได้รับการประเมิน ฯลฯ เช่นเดียวกับที่คุณค้นพบ

หากคุณต้องการขยายค่าบางค่า แต่ไม่ใช่ทั้งหมดคุณต้องหลีกเลี่ยงค่าที่คุณต้องการป้องกันทีละรายการ

cat <<EOF >>brightup.sh
#!/bin/sh
# Created on $(date # : <<-- this will be evaluated before cat;)
echo "\$HOME will not be evaluated because it is backslash-escaped"
EOF

จะผลิต

#!/bin/sh
# Created on Fri Feb 16 11:00:18 UTC 2018
echo "$HOME will not be evaluated because it is backslash-escaped"

ตามที่แนะนำโดย@fedorquiนี่คือส่วนที่เกี่ยวข้องจากman bash:

เอกสารที่นี่

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

รูปแบบของเอกสารที่นี่คือ:

      <<[-]word
              here-document
      delimiter

ไม่มีการขยายพารามิเตอร์การแทนที่คำสั่งการขยายเลขคณิตหรือการขยายชื่อพา ธ บน word หากมีการยกตัวอักษรใด ๆ ในคำตัวคั่นจะเป็นผลมาจากการลบเครื่องหมายคำพูดออกและบรรทัดในเอกสารที่นี่จะไม่ขยาย หากคำ unquoted เส้นทั้งหมดของที่นี่เอกสารอาจมีการขยายตัวพารามิเตอร์แทนคำสั่งและการขยายตัวทางคณิตศาสตร์ ในกรณีหลังลำดับอักขระ \ จะถูกละเว้นและ \ ต้องใช้เพื่ออ้างถึงอักขระ \, $ และ "


1
ฉันเห็นคุณทำเครื่องหมายว่าจะหลีกเลี่ยงการขยายตัวแปร heredoc ได้อย่างไร ซ้ำกับอันนี้ ไม่มีการคัดค้านเพียง แต่ฉันจะรวมการอ้างอิงเอกสาร Bash เหมือนที่ฉันทำในของฉัน (ซึ่งมีการเยี่ยมชมเพียง 13k ครั้งมีตัวแทนเกือบ 100 คนดังนั้นดูเหมือนว่าจะมีประโยชน์มาก)
fedorqui 'SO หยุดทำร้าย'

@fedorqui บางทีคุณอาจต้องการตอบคำถามนี้จริงหรือ? หรือเราสามารถเปลี่ยนการทำเครื่องหมายที่ซ้ำกันเป็นวิธีอื่นก็ได้ ฉันแค่ดูคะแนนคำถามไม่ใช่คะแนนคำตอบมากนัก
tripleee

อืมแล้วการรวมเข้าด้วยกันโดยให้คำถามนี้เป็นคำถามเป้าหมาย? คำถามที่ซ้ำกันมีชื่อที่ดีเพียงแต่ว่ายาวเกินไป อย่างไรก็ตามมันได้รับความสนใจค่อนข้างมากในช่วงปลายเดือน (ฉันได้รับการโหวตเพิ่มขึ้นต่อเดือน )
fedorqui 'SO หยุดทำร้าย'

@fedorqui ฉันชอบแนวคิดของการรวมกัน แต่ฉันไม่เคยเห็นมันเกิดขึ้นในทางปฏิบัติ ถ้าฉันเข้าใจสถานการณ์อย่างถูกต้อง mods ก็ไม่สามารถจัดการการผสานที่ไม่สำคัญได้เพราะความยุ่งยากและความซับซ้อนนั้นมีมากกว่าประโยชน์ สิ่งที่ฉันทำครั้งหรือสองครั้งคือลบคำตอบที่มีประโยชน์และเพิ่มคะแนนและโพสต์ใหม่ภายใต้คำถามอื่นแม้ว่าฉันแทบจะไม่สามารถแนะนำวิธีแก้ปัญหานี้ได้
tripleee

ยากที่จะบอกได้ว่าเมื่อใดควรทำ ฉันได้ทำในไซต์ที่ฉันแก้ไขเมื่อมีการโพสต์คำถามที่ดีโดยไม่สังเกตเห็นว่ามีอีกคำถามหนึ่งที่ดีจากก่อนหน้านี้ทั้งสองมีคำตอบที่ดี การลบคำตอบคะแนน 90+ ของฉันดูเหมือนจะไม่ใช่แผนการที่ดีเนื่องจากจะทำให้คำถามนั้นเป็นเด็กกำพร้า
fedorqui 'SO หยุดทำร้าย'

22

หรือใช้เครื่องหมาย EOF ของคุณคุณต้องอ้างเครื่องหมายเริ่มต้นจึงจะไม่สามารถขยายได้:

#-----v---v------
cat <<'EOF' >> brightup.sh
#!/bin/bash
curr=`cat /sys/class/backlight/intel_backlight/actual_brightness`
if [ $curr -lt 4477 ]; then
   curr=$((curr+406));
   echo $curr  > /sys/class/backlight/intel_backlight/brightness;
fi
EOF

IHTH


1
ฉันจะแก้ไขโพสต์ของคุณ แต่เพื่อความปลอดภัยไม่ควรเป็น #! / bin / bash ไม่ใช่! / bin / bash?
Matthew Hoggan

@MatthewHoggan: ใช่คุณถูกต้อง! ขอบคุณที่ติดตาม ฉันกำลังแก้ไขอยู่
กระสุน

17

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

cat <<< '
#!/bin/bash
curr=`cat /sys/class/backlight/intel_backlight/actual_brightness`
if [ $curr -lt 4477 ]; then
  curr=$((curr+406));
  echo $curr  > /sys/class/backlight/intel_backlight/brightness;
fi' > file # use overwrite mode so that you don't keep on appending the same script to that file over and over again, unless that's what you want. 

การใช้สิ่งต่อไปนี้ก็ใช้ได้เช่นกัน

cat <<< ' > file
 ... code ...'

นอกจากนี้ควรสังเกตว่าเมื่อใช้ heredocs เช่นการ<< EOFแทนที่และการขยายตัวแปรและสิ่งที่คล้ายกันจะเกิดขึ้น ดังนั้นการทำสิ่งนี้:

cat << EOF > file
cd "$HOME"
echo "$PWD" # echo the current path
EOF

จะส่งผลให้ตัวแปรขยายตัว$HOMEและ$PWD. ดังนั้นถ้าไดเรกทอรีบ้านของคุณเป็น/home/foobarและเส้นทางปัจจุบันคือ/home/foobar/bin, fileจะมีลักษณะเช่นนี้

cd "/home/foobar"
echo "/home/foobar/bin"

แทนที่จะเป็นที่คาดหวัง:

cd "$HOME"
echo "$PWD"

2
เห็นได้ชัดว่าสตริงที่นี่ในเครื่องหมายคำพูดเดี่ยวต้องไม่มีเครื่องหมายคำพูดเดียวซึ่งอาจเป็นปัญหาที่ต้องห้าม เอกสารต่อไปนี้เป็นวิธีแก้ปัญหาที่มีเหตุผลเพียงอย่างเดียวหากคุณมีสคริปต์ที่จำเป็นต้องมีทั้งเครื่องหมายคำพูดเดี่ยวและคู่แม้ว่าจะไม่เป็นเช่นนั้นกับตัวอย่างง่ายๆของ OP ก็ตาม นอกจากนี้ในเชิงสัมผัสสตริงที่นี่<<<จะมีให้ใช้งานตั้งแต่ Bash 3 เท่านั้นและไม่สามารถพกพาไปยังเชลล์อื่นได้
tripleee

<<<ยังมีให้บริการใน Zsh
Alexej Magura

3
วันนี้ฉันได้เรียนรู้ว่าคุณสามารถตั้งชื่อไฟล์ได้ทันทีหลังจากเปิดไปที่ heredoc ขอบคุณ @AlexejMagura!
Chaseadamsio

0

ฉันรู้ว่านี่เป็นคำถามเก่าสองปี แต่นี่เป็นคำตอบที่รวดเร็วสำหรับผู้ที่ค้นหา "วิธีการ"

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

#!/bin/bash

FILE_NAME="test.txt"
VAR_EXAMPLE="\"string\""

cat > ${FILE_NAME} << EOF
\${VAR_EXAMPLE}=${VAR_EXAMPLE} in ${FILE_NAME}  
EOF

จะเขียน "$ {VAR_EXAMPLE} =" string "ใน test.txt" ลงใน test.txt

นอกจากนี้ยังสามารถใช้เพื่อส่งออกบล็อกของข้อความไปยังคอนโซลด้วยกฎเดียวกันโดยการละชื่อไฟล์

#!/bin/bash

VAR_EXAMPLE="\"string\""

cat << EOF
\${VAR_EXAMPLE}=${VAR_EXAMPLE} to console 
EOF

จะส่งออก "$ {VAR_EXAMPLE} =" string "to console" ไปที่คอนโซล

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.