Yorumlu metinlerde (EOF) eko-n'ye benzer bir şey var mı?


12

Sunucularım için bakım komut dosyaları üreten büyük bir komut dosyası fabrika komut dosyası yazıyorum.

Şimdiye kadar, echo -neörneğin bir satırda yazılması gereken bazı satırlar yazıyorum.

echo -n "if (( " | sudo tee -a /usr/local/bin/upgradeAllServers &> /dev/null

# Generate exitCode check for each Server
IFS=" "
COUNT=0
while read -r name ipAddr
do
    if(($COUNT != 0))
    then
        echo -n " || " | sudo tee -a /usr/local/bin/upgradeAllServers &> /dev/null
    fi

    echo -n "(\$"$name"_E != 0 && \$"$name"_E != 1)" | sudo tee -a /usr/local/bin/upgradeAllServers &> /dev/null

    COUNT=$((COUNT+1))

    JOBSDONE=$((JOBSDONE+1))
    updateProgress $JOBCOUNT $JOBSDONE
done <<< "$(sudo cat /root/.virtualMachines)"

echo " ))" | sudo tee -a /usr/local/bin/upgradeAllServers &> /dev/null

bu beni (yapılandırma dosyamda 2 sunucu varsa) gibi kod üretir

if (( ($server1_E != 0 && $server1_E != 1) || ($server2_E != 0 && $server2_E != 1) ))

Yazma ve bakım için daha iyi bir yol bulduğumdan, yorumlu metinlerle ürettiğim bu satır içi kod yazımına ihtiyaç duymayan diğer tüm kod blokları. Örneğin, üst koddan sonra geri kalanı gibi oluşturulur

cat << EOF | sudo tee -a /usr/local/bin/upgradeAllServers &> /dev/null
then
    # Print out ExitCode legend
    echo " ExitCode 42 - upgrade failed"
    echo " ExitCode 43 - Upgrade failed"
    echo " ExitCode 44 - Dist-Upgrade failed"
    echo " ExitCode 45 - Autoremove failed"
    echo ""
    echo ""
fi
EOF

Son kod bloğu şöyle görünüyor

if (( ($server1_E != 0 && $server1_E != 1) || ($server2_E != 0 && $server2_E != 1) ))
then
    # Print out ExitCode legend
    echo " ExitCode 42 - upgrade failed"
    echo " ExitCode 43 - Upgrade failed"
    echo " ExitCode 44 - Dist-Upgrade failed"
    echo " ExitCode 45 - Autoremove failed"
    echo ""
    echo ""
fi

Benim
sorum Bir yorumcu echo -nesatır sonu sembolü olmadan benzer davranmanın bir yolu var mı ?


1
sudoBir betiğe ihtiyacınız varsa yanlış yapıyorsunuz: Bunun yerine betiğin tamamını root olarak çalıştırın!
tatlı

1
Hayır, çünkü aynı zamanda root olarak çalıştırmak istemediğim diğer şeyleri de yapıyor
derHugo

Kullanım sudo -u USERNAMEile ilgili olduğunu bunun yerine, bkz ben bir senaryo içinde bir 'sudo' komutunu nasıl çalıştırabilirim? .
tatlı

benim yaptığım gibi problem nedir?
derHugo

4
Tabii ki bir sorun var: sudoKullanıcı adı olmayan bir komut dosyası , şifreyi girmediğiniz sürece, sizden bir gecikme olmaz. Senaryoyu bir terminalde çalıştırmazsanız daha da kötüdür, o zaman şifre sorgusunu bile göremezsiniz ve sadece işe yaramaz. sudo -uYaklaşım bu sorunların hiçbirine sahip değildir.
tatlı

Yanıtlar:


9

Hayır, yorumlu metin her zaman yeni bir satırda sona erer. Ancak yine de son satırsonu, örneğin Perl ile kaldırabilirsiniz:

cat << 'EOF' | perl -pe 'chomp if eof'
First line
Second line
EOF
  • -pgirişi satır satır okur, belirtilen kodu çalıştırır -eve (muhtemelen değiştirilmiş) satırı yazdırır
  • chomp , varsa son satır sonunu kaldırır, eof dosyanın sonunda true değerini döndürür.

1
@Yaron karşılaşılan dosya sonu başına (bu durumda kapalı boru) başına son satırdan (heredoc ve herestring'in otomatik olarak eklediği şey) yeni satır karakterini keser
Sergiy Kolodyazhnyy

7

Satır sonu simgesi olmadan eko -ne'ye benzer bir yorumcuya sahip olmanın bir yolu var mı?

Kısa cevap, yorumlu metin ve yorumlamalar bu şekilde oluşturulmuştur, bu yüzden hayır - burada-doc ve herestring her zaman bir satırsonu ekleyecek ve devre dışı bırakmanın bir seçeneği veya yerel yolu yoktur (belki de gelecekteki bash sürümlerinde olacak?).

Bununla birlikte, sadece bash yollarıyla yaklaşmanın bir yolu, heredoc'un standart while IFS= read -ryöntemle ne verdiğini okumak , ancak bir gecikme eklemek ve son satırı printfolmadan son satırı yazdırmak olacaktır . Sadece bash ile neler yapılabilir:

#!/usr/bin/env bash

while true
do
    IFS= read -r line || { printf "%s" "$delayed";break;}
    if [ -n "$delayed" ]; 
    then
        printf "%s\n" "$delayed"
    fi
    delayed=$line
done <<EOF
one
two
EOF

Burada gördüğünüz IFS= read -r lineyaklaşım ile döngü halindeki olağan döngüdür , ancak her satır bir değişkende saklanır ve bu nedenle gecikir (bu nedenle ilk satırı yazdırmayı atlar, depolar ve yalnızca ikinci satırı okuduğumuzda yazdırmaya başlarız). Bu şekilde son satırı yakalayabiliriz ve bir sonraki yinelemede readçıkış durumu 1'i döndürdüğünde, son satırı yeni satır olmadan yazdırırız printf. Ayrıntılı mı? Evet. Ama işe yarıyor:

$ ./strip_heredoc_newline.sh                                      
one
two$ 

Yeni $satır olmadığından , komut isteminin öne doğru itildiğine dikkat edin . Bir bonus olarak, bu çözüm taşınabilir ve POSIX-ish'dir, bu yüzden kshhem dashde hem de çalışmalıdır.

$ dash ./strip_heredoc_newline.sh                                 
one
two$

6

Farklı bir yaklaşım denemenizi tavsiye ederim. Oluşturulan betiğinizi birden çok yankı deyiminden ve yorumlu metinlerden bir araya getirmek yerine. Tek bir heredoc kullanmaya çalışmanızı öneririm.

Bir heredoc içinde değişken genişletme ve komut ikamesi kullanabilirsiniz. Bu örnekteki gibi:

#!/bin/bash
cat <<EOF
$USER $(uname)
EOF

Bunun çoğu zaman çıktıyı parça parça üretmekten çok daha okunabilir sonuçlara yol açtığını düşünüyorum.

Ayrıca #!senaryolarınızın başlangıcındaki satırı unutmuş gibi görünüyorsunuz . #!Çizgi herhangi doğru biçimlendirilmiş komut zorunludur. Bir komut dosyasını #!satır olmadan çalıştırmayı denemek , yalnızca kötü biçimlendirilmiş komut dosyaları etrafında çalışan bir kabuktan çağırırsanız ve bu durumda bile istediğinizden farklı bir kabuk tarafından yorumlanmaya çalışabilir.


#!ama unuttu ama benim kod
bloğum

@derHugo Satırın bir döngüye ihtiyacınız olan kısmı için komut ikamesi bunu yapmanın bir yoludur. Başka bir yol, bu kısmı heredoc'tan önce bir değişkente inşa etmektir. İkisinden en okunabilir olanı, döngüde gereken kodun uzunluğuna ve söz konusu satırdan önce kaç tane heredoc satırına sahip olduğunuza bağlıdır.
kasperd

@derHugo Komut dosyasında daha önce tanımlanan bir kabuk işlevini çağıran komut ikamesi, bir satırı oluşturmak için önemli miktarda koda ihtiyacınız varsa daha okunabilir olabilecek üçüncü bir yaklaşımdır.
kasperd

@derHugo: Şunlara dikkat edin: (1) Gerekli tüm komutları bir değişkene yerleştiren bir döngünüz olabilir; (2) $( ...command...)Bir yorumlu yazılımın içinde, bu komutların çıktısını heredoc'ta o noktada satır içine eklemek için kullanabilirsiniz; (3) Bash, satır içi genişletebileceğiniz ve gerekirse başlangıç ​​/ bitiş öğelerini eklemek için ikameleri kullanabileceğiniz dizi değişkenlerine sahiptir. Bunlar birlikte kasperd'ün önerisini çok daha güçlü hale getirir (ve betiğiniz potansiyel olarak çok daha okunaklı hale gelir).
psmears

Benedocs şablon davranışları (wysiwyg) nedeniyle kullanıyorum. Tüm şablonun başka bir yerde üretilmesi ve bence heredoc'a iletilmesinden daha kolay okunması / sürdürülmesi kolay değildir.
derHugo

2

Yorumlu metinler her zaman yeni satır karakterleriyle biter, ancak bunu kaldırabilirsiniz. Bilmemin en kolay yolu headprogram:

head -c -1 <<EOF | sudo tee file > /dev/null
my
heredoc
content
EOF

Cool Bunun -cda olumsuz değerler aldığını bilmiyordum ! Bunun gibi pearlçözümden
derHugo

1

Yeni satırları istediğiniz gibi kaldırabilirsiniz, borulama trmuhtemelen en basit olacaktır. Bu elbette tüm yeni satırları kaldıracaktır.

$ tr -d '\n' <<EOF 
if ((
EOF

Ancak, oluşturduğunuz if ifadesi bunu gerektirmez, aritmetik ifade (( .. )), satırsonu içermesine rağmen iyi çalışmalıdır.

Yani, yapabilirsin

cat <<EOF 
if ((
EOF
for name in x y; do 
    cat << EOF
    ( \$${name}_E != 0 && \$${name}_E != 1 ) ||
EOF
done
cat <<EOF
    0 )) ; then 
    echo do something
fi
EOF

üreten

if ((
    ( $x_E != 0 && $x_E != 1 ) ||
    ( $y_E != 0 && $y_E != 1 ) ||
    0 )) ; then 
    echo do something
fi

Yine de bir döngü içinde inşa etmek hala çirkin hale geliyor. || 0Biz ilk veya son satırına özel durumda gerek kalmamasıdır Tabii böylece orada olduğunu.


Ayrıca, | sudo tee ...her çıktıda bu var. Sanırım bundan yalnızca bir kez (işlem ikamesi ile) bir yönlendirme açarak ve bunu daha sonraki yazdırma için kullanarak kurtarabiliriz:

exec 3> >(sudo tee outputfile &>/dev/null)
echo output to the pipe like this >&3
echo etc. >&3
exec 3>&-         # close it in the end

Ve açıkçası, hala dış komut dosyasında (böyle \$${name}_E) değişkenlerden değişken adları oluşturmanın biraz çirkin olduğunu düşünüyorum ve muhtemelen ilişkilendirilebilir bir dizi ile değiştirilmesi gerekir .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.