การใช้ตัวแปรภายใน bash heredoc


192

ฉันพยายามแก้ไขตัวแปรภายใน bash heredoc:

var=$1
sudo tee "/path/to/outfile" > /dev/null << "EOF"
Some text that contains my $var
EOF

สิ่งนี้ไม่ทำงานอย่างที่ฉันคาดไว้ ( $varได้รับการปฏิบัติอย่างแท้จริงไม่ขยาย)

ฉันต้องใช้sudo teeเพราะการสร้างไฟล์ต้องใช้ sudo ทำสิ่งที่ชอบ:

sudo cat > /path/to/outfile <<EOT
my text...
EOT

ไม่ทำงานเพราะ>outfileเปิดไฟล์ในเชลล์ปัจจุบันซึ่งไม่ได้ใช้งาน sudo


9
นี่เป็นความสับสนที่เข้าใจได้! ดังที่ระบุไว้ด้านล่างการอ้างถึงส่วนใด ๆ ของตัวคั่นจะปิดการขยายใน heredoc (ราวกับว่ามันอยู่ใน'') แต่ไม่ได้อ้างถึงตัวคั่นจะเปิดการขยายตัว (เช่นถ้าอยู่ใน"") อย่างไรก็ตามสัญชาตญาณของคุณถูกต้องใน Perl โดยที่ heredoc ที่มีตัวระบุที่เสนอราคาเดียวจะทำงานเหมือนกับว่าอยู่ในเครื่องหมายคำพูดเดี่ยวหนึ่งที่มีตัวระบุคู่ที่ยกมาราวกับว่าในเครื่องหมายคำพูดคู่และหนึ่งที่มีตัวบ่งชี้ย้อนกลับราวกับว่าใน backticks ! ดู: perlop: << EOF
Nils von Barth

คำตอบ:


252

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

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

      <<[-]word
              here-document
      delimiter

ไม่มีการขยายตัวพารามิเตอร์แทนคำสั่งขยายตัวทางคณิตศาสตร์หรือการขยายตัวของพา ธ ที่จะดำเนินการในคำ หากอักขระใด ๆ ในคำถูกยกมา ตัวคั่นเป็นผลมาจากการลบคำพูดในคำและบรรทัดในที่นี่เอกสารจะไม่ขยาย หากคำไม่ได้อยู่ในเครื่องหมายคำพูดบรรทัดทั้งหมดของ here-document จะอยู่ภายใต้การขยายพารามิเตอร์การทดแทนคำสั่งและการขยายเลขคณิต [ ... ]

หากคุณเปลี่ยนตัวอย่างแรกเพื่อใช้<<EOFแทนคุณ<< "EOF"จะพบว่าใช้งานได้

ในตัวอย่างที่สองของคุณเชลล์จะเรียกใช้sudoเฉพาะกับพารามิเตอร์catและการเปลี่ยนเส้นทางจะใช้กับเอาต์พุตของsudo catในฐานะผู้ใช้ดั้งเดิม มันจะทำงานถ้าคุณลอง:

sudo sh -c "cat > /path/to/outfile" <<EOT
my text...
EOT

หากสนใจของคุณคุณยังสามารถทำเช่นนี้: (cat > /path/to/outfile) <<EOFในสถานที่ของsudo sh -c ... <<EOF
วอลแตร์

โปรดบอกฉันที่ฝังใน Bash เป็นเหตุผลที่ดีว่าทำไมจึงเป็นเช่นนี้
Landon Kuhn

96

อย่าใช้เครื่องหมายคำพูดกับ<<EOF:

var=$1
sudo tee "/path/to/outfile" > /dev/null <<EOF
Some text that contains my $var
EOF

การขยายตัวแปรเป็นพฤติกรรมเริ่มต้นภายใน here-docs คุณปิดใช้งานพฤติกรรมดังกล่าวโดยการอ้างอิงป้ายกำกับ (ด้วยเครื่องหมายคำพูดเดี่ยวหรือคู่)


36

ในฐานะที่เป็น corolloary ปลายของคำตอบก่อนหน้านี้ที่นี่คุณอาจท้ายในสถานการณ์ที่คุณต้องการตัวแปรบางอย่างแต่ไม่ทั้งหมดจะถูกแก้ไข คุณสามารถแก้ไขได้โดยใช้แบ็กสแลชเพื่อหลีกเลี่ยงสัญญาณดอลลาร์และ backticks; หรือคุณสามารถใส่ข้อความคงที่ในตัวแปร

Name='Rich Ba$tard'
dough='$$$dollars$$$'
cat <<____HERE
$Name, you can win a lot of $dough this week!
Notice that \`backticks' need escaping if you want
literal text, not `pwd`, just like in variables like
\$HOME (current value: $HOME)
____HERE

การสาธิต: https://ideone.com/rMF2XA

โปรดทราบว่ากลไกการอ้างอิงใด ๆ - \____HEREหรือ"____HERE"หรือ'____HERE'- จะปิดใช้งานการแก้ไขตัวแปรทั้งหมดและเปลี่ยนเอกสารที่นี่เป็นข้อความตัวอักษร

ภารกิจทั่วไปคือการรวมตัวแปรโลคัลกับสคริปต์ซึ่งควรประเมินโดยเชลล์ภาษาการเขียนโปรแกรมหรือรีโมตโฮสต์อื่น

local=$(uname)
ssh -t remote <<:
    echo "$local is the value from the host which ran the ssh command"
    # Prevent here doc from expanding locally; remote won't see backslash
    remote=\$(uname)
    # Same here
    echo "\$remote is the value from the host we ssh:ed to"
:

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