سؤال طريقة نظيفة لكتابة سلسلة متعددة الأسطر معقدة لمتغير


أحتاج إلى كتابة بعض xml المعقدة إلى متغير داخل برنامج نصي bash. يجب أن تكون لغة xml قابلة للقراءة داخل البرنامج النصي bash لأن هذا هو المكان الذي ستعيش فيه جزء xml ، ولا يتم قراءته من ملف أو مصدر آخر.

لذا فإن سؤالي هو هذا إذا كان لديّ سلسلة طويلة أريد أن أكون قابلة للقراءة من قِبَلها داخل سكربتي bash ، فما هي أفضل طريقة لذلك؟

من الناحية المثالية أريد:

  • ليس من الضروري الهروب من أي من الشخصيات
  • هل لديك اختراق خطوط متعددة مما يجعلها مقروءة البشرية
  • ابق على المسافة البادئة

يمكن أن يتم ذلك مع EOF أو شيء من هذا ، يمكن لأي شخص أن تعطيني مثالا؟

مثلا

String = <<EOF
 <?xml version="1.0" encoding='UTF-8'?>
 <painting>
   <img src="madonna.jpg" alt='Foligno Madonna, by Raphael'/>
   <caption>This is Raphael's "Foligno" Madonna, painted in
   <date>1511</date>-<date>1512</date>.</caption>
 </painting>
EOF

94
2017-10-08 10:54


الأصل


أنا على استعداد للمراهنة على أنك ستقوم فقط بتفريغ تلك البيانات في جدول مرة أخرى. لماذا يتم تخزينها في متغير عندما يمكنك جعل الأشياء أكثر تعقيدًا واستخدام التدفقات؟ - Zenexer
انظر هذا أيضا: سلسلة متعددة الخطوط مع مساحة إضافية (المسافة البادئة المحفوظة) - Yibo Yang


الأجوبة:


سيؤدي ذلك إلى وضع النص في المتغير دون الحاجة إلى الهروب من علامات الاقتباس. كما سيتعامل مع الاقتباسات غير المتوازنة (apostrophes ، أي '). وضع علامات الاقتباس حول الحارس (EOF) يمنع النص من قيد التوسع المعلمة. ال -d'' يتسبب في قراءة عدة أسطر (تجاهل الخطوط الجديدة). read هو باش مدمج بحيث لا يتطلب الأمر استدعاء أمر خارجي مثل cat.

IFS='' read -r -d '' String <<"EOF"
<?xml version="1.0" encoding='UTF-8'?>
 <painting>
   <img src="madonna.jpg" alt='Foligno Madonna, by Raphael'/>
   <caption>This is Raphael's "Foligno" Madonna, painted in
   <date>1511</date>-<date>1512</date>.</caption>
 </painting>
EOF

123
2017-10-08 12:37



+1 لتجنب cat. - James Sneeringer
cat هو أمر خارجي. عدم استخدامه يحفظ القيام بذلك. بالإضافة إلى ذلك ، لدى البعض فلسفة مفادها أنه إذا كنت تستخدم قطة ذات حجج أقل من حجتين "Ur doin 'it wrong" (وهو يختلف عن "الاستخدام غير المجدي لل cat"). - Dennis Williamson
وأبدا أبدا مسافة بادئة EOF الثانية .... (جدول متعددة لرأس الانفجارات المعنية) - IljaBek
حاولت استخدام العبارة أعلاه بينما set -e. يبدو read عاد دائما غير الصفر. يمكنك ثخين هذا السلوك باستخدام ! read -d ....... - krissi
وإذا كنت تستخدم هذا متعدد الخطوط String متغير للكتابة إلى ملف ، ووضع المتغير حول "QUOTES" مثل echo "${String}" > /tmp/multiline_file.txt أو echo "${String}" | tee /tmp/multiline_file.txt. استغرقني أكثر من ساعة للعثور على ذلك. - Aditya


كنت هناك تقريبا. إما أن تستخدم قط لتجميع السلسلة الخاصة بك أو يمكنك اقتباس السلسلة بأكملها (في هذه الحالة يجب عليك الهروب من علامات الاقتباس داخل السلسلة):

#!/bin/sh
VAR1=$(cat <<EOF
<?xml version="1.0" encoding='UTF-8'?>
<painting>
  <img src="madonna.jpg" alt='Foligno Madonna, by Raphael'/>
  <caption>This is Raphael's "Foligno" Madonna, painted in
  <date>1511</date>-<date>1512</date>.</caption>
</painting>
EOF
)

VAR2="<?xml version=\"1.0\" encoding='UTF-8'?>
<painting>
  <img src=\"madonna.jpg\" alt='Foligno Madonna, by Raphael'/>
  <caption>This is Raphael's \"Foligno\" Madonna, painted in
  <date>1511</date>-<date>1512</date>.</caption>
</painting>"

echo "${VAR1}"
echo "${VAR2}"

25
2017-10-08 11:14



لسوء الحظ ، الفاصلة العليا في "Raphael's" تجعل الأولى لا تعمل. - Dennis Williamson
كلا الواجبات تعمل لي في نهاية المطاف. يجب ألا يكون الاقتباس المفرد في VAR1 مشكلة (على الأقل ليس لباش). ربما كنت قد ضلل من قبل تسليط الضوء على بناء الجملة؟ - joschi
وهو يعمل في برنامج نصي ، ولكن ليس في موجه Bash. آسف لعدم الوضوح. - Dennis Williamson
من الأفضل الإشارة إلى EOF كـ 'EOF' أو "EOF"، وإلا سيتم تحليل متغيرات shell. - Stanislav German-Evtushenko


#!/bin/sh

VAR1=`cat <<EOF
<?xml version="1.0" encoding='UTF-8'?>
<painting>
  <img src="madonna.jpg" alt='Foligno Madonna, by Raphael'/>
  <caption>This is Raphael's "Foligno" Madonna, painted in
  <date>1511</date>-<date>1512</date>.</caption>
</painting>
EOF
`
echo "VAR1: ${VAR1}"

هذا يجب أن تعمل بشكل جيد داخل بيئة shell Bourne


9
2017-09-05 15:54



يسمح إجراء 1+ لهذا الحل بإبدال متغير مثل $ {foo} - Offirmo
الجانب العلوي: sh-compatible. الجانب السلبي: يتم إهمال عناصر البكرة / الإقصاء في باش. الآن إذا اضطررت إلى الاختيار بين sh و bash ... - Zenexer
منذ متى يتم إيقاف ساعات العمل الخلفية / الإحباط؟ فضولي فقط - Alexander Mills


طريقة أخرى لفعل الشيء نفسه ...

أحب استخدام المتغيرات والخاصة <<- من يسقط جدولة في بداية كل سطر للسماح بادئة البرنامج النصي:

#!/bin/bash

mapfile Pattern <<-eof
        <?xml version="1.0" encoding='UTF-8'?>
        <painting>
          <img src="%s" alt='%s'/>
          <caption>%s, painted in
          <date>%s</date>-<date>%s</date>.</caption>
        </painting>
        eof

while IFS=";" read file alt caption start end ;do
    printf "${Pattern[*]}" "$file" "$alt" "$caption" "$start" "$end"
  done <<-eof
        madonna.jpg;Foligno Madonna, by Raphael;This is Raphael's "Foligno" Madonna;1511;1512
        eof

تحذير: لا يوجد مساحة فارغة قبل eof لكن فقط جدولة.

<?xml version="1.0" encoding='UTF-8'?>
 <painting>
   <img src="madonna.jpg" alt='Foligno Madonna, by Raphael'/>
   <caption>This is Raphael's "Foligno" Madonna, painted in
   <date>1511</date>-<date>1512</date>.</caption>
 </painting>
بعض التفسيرات:
  • mapfile قراءة كاملة هنا الوثيقة في صفيف.
  • بناء الجملة "${Pattern[*]}" لا يلقي هذا المصفوفة في سلسلة.
  • أنا أستعمل IFS=";" لأنه لا يوجد ; في السلاسل المطلوبة
  • بناء الجملة while IFS=";" read file ... يحول دون IFS ليتم تعديله لبقية البرنامج النصي. في هذا ، فقط read لا تستخدم تعديلها IFS.
  • لا شوكة.

4
2017-07-22 13:45



لاحظ أن mapfile يتطلب Bash 4 أو أعلى. والبناء "${Pattern[*]}" يلقي المصفوفة في سلسلة عندما في الاقتباس (كما هو موضح في كود المثال). - Dennis Williamson
نعم ، كان باش 4 جدا الجديد عندما سئل هذا السؤال. - F. Hauri


هناك العديد من الحالات الزاوية في العديد من الإجابات الأخرى.

للتأكد من عدم وجود مشاكل مع المسافات ، علامات التبويب ، IFS ، إلخ ، فإن الطريقة الأفضل هي استخدام بنية "heredoc" ، ولكن قم بتشفير محتويات الوراثة باستخدام uuencode كما هو موضح هنا:

https://stackoverflow.com/questions/6896025/#11379627.


2
2018-05-17 09:10