เชลล์ - เขียนเนื้อหาตัวแปรลงในไฟล์


98

ฉันต้องการคัดลอกเนื้อหาของตัวแปร (ในที่นี้เรียกว่าvar) ลงในไฟล์

destfileชื่อของไฟล์จะถูกเก็บไว้ในตัวแปรอื่น

ฉันมีปัญหาในการดำเนินการนี้ นี่คือสิ่งที่ฉันได้ลอง:

cp $var $destfile

ฉันได้ลองสิ่งเดียวกันกับคำสั่ง dd ด้วย ... เห็นได้ชัดว่าเชลล์คิดว่า$varอ้างถึงไดเร็กทอรีจึงบอกฉันว่าไม่พบไดเร็กทอรี

ฉันจะหลีกเลี่ยงสิ่งนี้ได้อย่างไร?


2
โปรดปรับปรุงคำถามของคุณโดยการโพสต์โค้ดที่มีรูปแบบถูกต้องซึ่งแสดงให้เห็นว่าคุณกำลังเติมตัวแปรของคุณอย่างไรและข้อความแสดงข้อผิดพลาดที่เกี่ยวข้องทั้งหมดตามที่ปรากฏ
Todd A.Jacobs

2
"คัดลอกเนื้อหาของตัวแปร" ไปยังไดเร็กทอรีหมายความว่าอย่างไร ไม่$varระบุชื่อแฟ้มหรือข้อความบางอย่างที่ควรจะเขียนไปยังแฟ้มหรือไม่? หากระบุข้อความชื่อของไฟล์ที่คุณต้องการเขียนเนื้อหานี้คืออะไร
jahroy

$ var มีข้อความที่ฉันต้องการจะคัดลอกและไฟล์ที่ควรเขียนนั้นถูกกำหนดโดยผู้ใช้ด้วยเหตุนี้ฉันจึงใช้ตัวแปรในตอนแรก
user1546083

1
บางที$destdirควรตั้งชื่อ$destfileเพื่อไม่ให้เข้าใจผิด ... ชื่อ$destdirแนะนำระบุไดเร็กทอรีมากกว่าไฟล์ สิ่งนี้จะทำให้คำถามทั้งหมดของคุณตรงประเด็นและเข้าใจง่าย
jahroy

คำตอบ:


149

ใช้echoคำสั่ง:

var="text to append";
destdir=/some/directory/path/filename

if [ -f "$destdir" ]
then 
    echo "$var" > "$destdir"
fi

การifทดสอบที่$destdirแสดงถึงไฟล์

ต่อ>ท้ายข้อความหลังจากตัดทอนไฟล์ หากคุณต้องการต่อท้ายข้อความใน$varเนื้อหาที่มีอยู่ของไฟล์ให้ใช้>>แทน:

echo "$var" >> "$destdir"

cpคำสั่งที่ใช้สำหรับการคัดลอกไฟล์ (กับไฟล์) ไม่ได้สำหรับการเขียนข้อความไปยังแฟ้ม


4
ต้องการคำพูดเพิ่มเติม - ตอนนี้การเว้นวรรคใด ๆ ภายในค่าของตัวแปรจะถูกแปลงเป็นช่องว่างเดียวการแสดงออกของลูกโลกจะถูกขยายเป็นต้น
Charles Duffy

2
อีกอย่างหนึ่ง - คุณต้องมีช่องว่างระหว่างเครื่องหมายคำพูดปิดและ]ใน"$destdir"].
Charles Duffy

3
echoยังเพิ่มบรรทัดใหม่ต่อท้ายตัวแปรของคุณ
Ben Dilts

6
สิ่งนี้ล้มเหลวถ้า$varเป็น-e text to appendและไม่ได้เขียน-e
Eric

1
เนื่องจากecho $varอาศัยเชลล์เพื่อขยายตัวแปรของคุณจึงไม่ได้ผลกับสิ่งต่างๆเช่นพื้นที่สีขาวและอักขระพิเศษ คุณสามารถใช้perl -e 'print($ENV{var})'แทนได้และจะแสดงผลค่าของตัวแปรอย่างแม่นยำ
Blake Mitchell

41

echoมีปัญหาว่าหากvarมีสิ่งที่ต้องการ-eมันจะถูกตีความว่าเป็นแฟล็ก อีกทางเลือกหนึ่งคือprintfแต่printf "$var" > "$destdir"จะขยายอักขระที่ใช้ Escape ในตัวแปรดังนั้นหากตัวแปรมีเครื่องหมายแบ็กสแลชเนื้อหาไฟล์จะไม่ตรงกัน อย่างไรก็ตามเนื่องจากprintfตีความเฉพาะแบ็กสแลชเป็นค่า Escape ในสตริงรูปแบบคุณสามารถใช้ตัว%sระบุรูปแบบเพื่อเก็บเนื้อหาตัวแปรที่แน่นอนไปยังไฟล์ปลายทาง:

printf "%s" "$var" > "$destdir"


1
printf ยังดีถ้าคุณมีการขึ้นบรรทัดใหม่ในสตริงตัวแปรเช่นจากคำพูดสามคำหรือ heredoc เสียงสะท้อนไม่สามารถรองรับการขึ้นบรรทัดใหม่ได้ดี
beeflobill

@beeflobill คุณช่วยอธิบายได้ไหมว่า "เสียงสะท้อนไม่สามารถจัดการกับข่าวใหม่ได้" สิ่งเดียวที่ฉันเห็นคือเสียงสะท้อนเพิ่มบรรทัดใหม่ ซึ่งจะทำให้echo "$var" > destfileผิด
SensorSmith

@SensorSmith ในการทดลองของฉันฉันเห็นว่าเมื่อสตริงมี "\ n" เสียงสะท้อนนั้นจะพิมพ์อักขระขึ้นบรรทัดใหม่ แต่ถ้าสตริงมีอักขระขึ้นบรรทัดใหม่จริงที่ echo จะไม่พิมพ์ออกมา ฉันไม่รู้ว่าทำไม
beeflobill

1
โดยทั่วไปปัญหาการพกพา (และความน่าเชื่อถือ) unix.stackexchange.com/a/65819 …หรือเพื่อความตายในหมู่พวกเรา: printfดีกว่าเดินหน้าต่อไป
user3342816

30

คำตอบข้างต้นไม่ได้ผลถ้าตัวแปรของคุณ:

  • เริ่มต้นด้วย -e
  • เริ่มต้นด้วย -n
  • เริ่มต้นด้วย -E
  • มี\ตามด้วยn
  • ไม่ควรมีบรรทัดใหม่เพิ่มเติมต่อท้าย

ดังนั้นจึงไม่สามารถพึ่งพาเนื้อหาสตริงที่กำหนดเองได้

ใน bash คุณสามารถใช้ "here strings" เป็น:

cat <<< "$var" > "$destdir"

ตามที่ระบุไว้ในความคิดเห็นด้านล่างคำตอบของ @ Trebawa (สูตรในห้องเดียวกับของฉัน!) โดยใช้printfเป็นแนวทางที่ดีกว่า


5
จากสิ่งที่ฉันบอกได้ cat จะแทรกขึ้นบรรทัดใหม่ที่ท้ายไฟล์เสมอไม่ว่าจะไม่มีการขึ้นบรรทัดใหม่ที่ท้ายตัวแปรก็ตาม (แม้ว่าเนื้อหาส่วนใหญ่จะเป็นสิ่งที่ดีก็ตาม) คำตอบโดยใช้ printfดูเหมือนว่าจะหลีกเลี่ยงการใส่อักขระขึ้นบรรทัดใหม่
Ash

@Ash ประโยชน์ของผู้อื่นprintfมากกว่าcatคือการที่อดีตเป็นเปลือก builtin ซึ่งมักจะดำเนินการเร็วกว่าไบนารีภายนอก
GézaTörök

7

ถ้าฉันเข้าใจคุณถูกต้องคุณต้องการคัดลอก$varไฟล์ (ถ้าเป็นสตริง)

echo $var > $destdir

นี่คือวิธีการทำ การใช้cpคำสั่งจะทำให้เชลล์ตีความอาร์กิวเมนต์แรกเป็นชื่อของไฟล์หรือไดเร็กทอรี
jahroy

5
หากคุณไม่ใส่$varเครื่องหมายคำพูดเนื้อหาของไฟล์จะไม่เท่ากับ 100% กับเนื้อหาของ $ var ในบางกรณี ตัวอย่างเช่นเมื่อ "echoing" vars ที่มีคีย์ RSA คุณจะได้รับคีย์ที่ไม่ถูกต้องในไฟล์
srigi

6
ล้มเหลวหาก$varมีช่องว่างหรือ-e
Eric

1

เมื่อคุณพูดว่า "คัดลอกเนื้อหาของตัวแปร" ตัวแปรนั้นมีชื่อไฟล์หรือไม่หรือมีชื่อไฟล์หรือไม่

ฉันคิดว่าคำถามของคุณ$varมีเนื้อหาที่คุณต้องการคัดลอกลงในไฟล์:

$ echo "$var" > "$destdir"

สิ่งนี้จะสะท้อนค่าของ $ var ลงในไฟล์ชื่อ $ destdir หมายเหตุคำพูด สำคัญมากที่จะต้องมี "$ var" อยู่ในเครื่องหมายคำพูด สำหรับ "$ destdir" หากมีช่องว่างในชื่อ ในการต่อท้าย:

$ echo "$var" >> "$destdir"

3
ล้มเหลวหากvarมี-e
Eric

1
การส่งยัติภังค์สองครั้งเป็นอาร์กิวเมนต์แรกเพื่อecho ยุติรายการตัวเลือกจึงช่วยแก้ปัญหาที่echo -- "$var" >> "$destfile"
@Eric

1

งานทั้งหมดข้างต้น แต่ยังต้องแก้ไขปัญหา (Escape และอักขระพิเศษ) ที่ไม่จำเป็นต้องเกิดขึ้นตั้งแต่แรก: อักขระพิเศษเมื่อตัวแปรถูกขยายโดยเชลล์ อย่าทำอย่างนั้น (การขยายตัวแปร) ตั้งแต่แรก ใช้ตัวแปรโดยตรงโดยไม่ต้องขยาย

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

ใช้สิ่งนี้:

printenv var >file

นั่นหมายความว่าในกรณีของคำถาม OP:

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