Bash devam hatları


158

Bash devam hatlarını nasıl kullanıyorsunuz?

Bunu yapabileceğinizin farkındayım:

echo "continuation \
lines"
>continuation lines

Ancak, girintili kod varsa, çok iyi çalışmaz:

    echo "continuation \
    lines"
>continuation     lines

5
Google'ın Bash Shell Stil Kılavuzu , "80 karakterden uzun dizeler yazmanız gerekiyorsa" için "burada" dokümanlarını önerir . Bakınız @ tripleee'nin cevabı .
Trevor Boyd Smith

google.github.io/styleguide/… - bu yeni belgedeki doğrudan bağlantıdır
jcollum

Yanıtlar:


161

İstediğiniz budur

$       echo "continuation"\
>       "lines"
continuation lines

Bu yankı için iki argüman yaratıyorsa ve sadece bir tane istiyorsanız, dize birleşimine bakalım. Bash'da, iki dizeyi yan yana yerleştirerek bitiştirin:

$ echo "continuation""lines"
continuationlines

Yani bir devam çizgi bir girinti olmaksızın bir dize kırmaya bir yoludur:

$ echo "continuation"\
> "lines"
continuationlines

Ancak bir girinti kullanıldığında:

$       echo "continuation"\
>       "lines"
continuation lines

İki bağımsız değişken elde edersiniz çünkü bu artık bir birleştirme değildir.

Satırları keserken tek bir dize istiyorsanız, girintileme yaparken ancak tüm bu boşlukları alamıyorsanız, deneyebileceğiniz bir yaklaşım, devam çizgisini atmak ve değişkenleri kullanmaktır:

$ a="continuation"
$ b="lines"
$ echo $a$b
continuationlines

Bu, ek değişkenler pahasına temiz bir şekilde girintili kod elde etmenizi sağlayacaktır. Değişkenleri yerel yaparsanız, çok kötü olmamalıdır.


1
Yardımınız için teşekkürler, ancak bu boşlukları kaldırırken, şimdi ayrı parametrelerdir (Bash ikinci satırdaki boşlukları bir parametre ayırıcısı olarak yorumlar) ve şimdi sadece echo komutu nedeniyle doğru yazdırılır.

1
Oh, satırları yaymak için tek bir bash dize istiyorsunuz! Şimdi görüyorum.
Ray Toal

4
Tek değişkenli çözüm:s="string no. 1" s+="string no. 2" s+=" string no. 3" echo "$s"
Johnny Thunderman

30

Burada <<-HEREsonlandırıcılı belgeler girintili çok satırlı metin dizeleri için iyi çalışır. Buradaki tüm önde gelen sekmeleri kaldırır. (Yine de hat sonlandırıcılar kalacaktır.)

cat <<-____HERE
    continuation
    lines
____HERE

Ayrıca bkz. Http://ss64.com/bash/syntax-here.html

Tümü olmasa da önde gelen boşlukları korumanız gerekiyorsa, aşağıdaki gibi bir şey kullanabilirsiniz.

sed 's/^  //' <<____HERE
    This has four leading spaces.
    Two of them will be removed by sed.
____HERE

veya tryeni satırlardan kurtulmak için kullanın :

tr -d '\012' <<-____
    continuation
     lines
____

(İkinci satırda bir sekme ve önde bir boşluk vardır; sekme, yorumlu sonlandırıcıdan önce tire operatörü tarafından kaldırılacak, oysa alan korunacaktır.)

Uzun karmaşık dizeleri birçok satıra sarmak için printf:

printf '%s' \
    "This will all be printed on a " \
    "single line (because the format string " \
    "doesn't specify any newline)"

Ayrıca, ana bilgisayar dilinin sözdiziminin a Makefileveya gibi bir burada belgeyi kullanmanıza izin vermeyeceği başka bir dilde önemsiz olmayan kabuk komut dosyası parçalarını gömmek istediğiniz bağlamlarda da iyi çalışır Dockerfile.

printf '%s\n' >./myscript \
    '#!/bin/sh` \
    "echo \"G'day, World\"" \
    'date +%F\ %T' && \
chmod a+x ./myscript && \
./myscript

Benim için çalışmıyor. Ubuntu 16.04. Beklenen birleştirilmiş bir satır yerine iki satır alıyorum.
Penghe Geng

@PengheGeng Gerçekten, bu, satırlara katılma değil, girintiden kurtulma sorununu çözüyor. İki çizgiyi birleştirmek için bir satırın sonundaki satırsonunu yine ters eğebilirsiniz.
tripleee

(Ama printfşimdi de ilk örneğe bakın .)
üçlü

12

Bash dizilerini kullanabilirsiniz

$ str_array=("continuation"
             "lines")

sonra

$ echo "${str_array[*]}"
continuation lines

ekstra bir alan var, çünkü (bash kılavuzundan sonra):

Sözcük çift tırnak içine alınmışsa, ${name[*]}her dizi üyesinin değeri IFS değişkeninin ilk karakteriyle ayrılmış tek bir sözcüğe genişler

IFS=''Ekstra alandan kurtulmak için ayarlanmış

$ IFS=''
$ echo "${str_array[*]}"
continuationlines

4

Bazı senaryolarda Bash'ın birleştirme yeteneğini kullanmak uygun olabilir.

Misal:

temp='this string is very long '
temp+='so I will separate it onto multiple lines'
echo $temp
this string is very long so I will separate it onto multiple lines

Bash Man sayfasının PARAMETRELER bölümünden:

isim = [değer] ...

... Bir atama ifadesinin kabuk değişkenine veya dizi dizinine bir değer atadığı bağlamda, + = operatörü değişkenin önceki değerine eklemek veya bu değere eklemek için kullanılabilir. Tamsayı özniteliğinin ayarlandığı bir değişkene + = uygulandığında, değer aritmetik bir ifade olarak değerlendirilir ve değişkenin geçerli değerine eklenir, bu değer de değerlendirilir. Bileşik ataması kullanılarak bir dizi değişkenine + = uygulandığında (aşağıdaki Diziler'e bakın), değişkenin değeri ayarlanmamıştır (= kullanılırken olduğu gibi) ve dizinin maksimum dizininden birinden başlayarak diziye yeni değerler eklenir (dizine alınmış diziler için) veya ilişkilendirilebilir bir dizide ek anahtar / değer çiftleri olarak eklenir. Dize değerli bir değişkene uygulandığında, değer genişletilir ve değişkenin değerine eklenir.


Muhtemelen bu sayfadaki en iyi tavsiye. Bir HEREDOC kullanmak ve <CR> s için bir çeviriye boru kullanmak süper sezgisel değildir ve dizenin gerçekten ayrı bir şekilde satır ayırıcılara sahip olması gerektiğinde başarısız olur.
Ocak'ta

2

Bir komut argümanının parçası olarak uzun bir mesaj göndermek zorunda olduğum ve satır uzunluğu sınırlamasına uymak zorunda kaldığım bir durumla karşılaştım. Komutlar şöyle görünür:

somecommand --message="I am a long message" args

Bunu çözdüğüm yol, mesajı burada bir belge olarak (@tripleee önerilen gibi) dışarı taşımaktır. Ama burada bir belge stdin oluyor, bu yüzden tekrar okunması gerekiyor, aşağıdaki yaklaşımla gittim:

message=$(
    tr "\n" " " <<- END
        This is a
        long message
END
)
somecommand --message="$message" args

Bunun avantajı, $messageekstra boşluk veya satır kesmeleri olmadan tam olarak dize sabiti olarak kullanılabilmesidir.

Yukarıdaki gerçek mesaj satırlarının tabher birinin, burada kullanıldığından (kullanımından dolayı <<-) ayrılan bir karakterle öneki olduğuna dikkat edin . Sonunda hala satır araları var ve bunlar ddboşluklarla değiştiriliyor .

Ayrıca, yeni satırları kaldırmazsanız, bu satırlar "$message"genişletildiğinde olduğu gibi görüneceğini unutmayın . Bazı durumlarda, çift tırnak işaretlerini kaldırarak geçici çözüm bulabilirsiniz $message, ancak ileti artık tek bir bağımsız değişken olmayacaktır.


2

Satır devamları sözdiziminin akıllıca kullanılmasıyla da sağlanabilir.

Aşağıdaki durumlarda echo:

# echo '-n' flag prevents trailing <CR> 
echo -n "This is my one-line statement" ;
echo -n " that I would like to make."
This is my one-line statement that I would like to make.

Vars durumunda:

outp="This is my one-line statement" ; 
outp+=" that I would like to make." ; 
echo -n "${outp}"
This is my one-line statement that I would like to make.

Varlık durumunda başka bir yaklaşım:

outp="This is my one-line statement" ; 
outp="${outp} that I would like to make." ; 
echo -n "${outp}"
This is my one-line statement that I would like to make.

İşte bu kadar!


1

Girintinin içinde gerektiği gibi yeni satırlarla (ters eğik çizgi kullanmadan) ve yalnızca yeni satır şeridi ile ayırabilirsiniz.

Misal:

echo "continuation
of 
lines" | tr '\n' ' '

Veya değişken bir tanımsa, yeni satırlar otomatik olarak boşluklara dönüştürülür. Bu nedenle, yalnızca varsa ek boşlukları soyun.

x="continuation
of multiple
lines"
y="red|blue|
green|yellow"

echo $x # This will do as the converted space actually is meaningful
echo $y | tr -d ' ' # Stripping of space may be preferable in this case

1

Bu tam olarak kullanıcının sorduğu bir şey değildir, ancak birden fazla satıra yayılan uzun bir dize oluşturmanın başka bir yolu, bunu aşamalı olarak oluşturmaktır:

$ greeting="Hello"
$ greeting="$greeting, World"
$ echo $greeting
Hello, World

Açıkçası bu durumda bir seferlik inşa etmek daha kolay olurdu, ancak bu stil daha uzun dizelerle uğraşırken çok hafif ve anlaşılabilir olabilir.


0

Ancak, girintili kod varsa, çok iyi çalışmaz:

    echo "continuation \
    lines"
>continuation     lines

Tek tırnak işareti ve dizeleri birleştirmeyi deneyin:

    echo 'continuation' \
    'lines'
>continuation lines

Not: birleştirme bir boşluk içerir.


2
Yankı ve dize bağımsız değişkenleriyle çalışır, ancak değişken ataması gibi başka şeylerle çalışmaz. Soru değişkenlerle ilgili olmasa da, yankı kullanmak sadece bir örnektir. Yerine echo sen olsaydı x=, hatayı almak istiyorum: lines: command not found.
LS

0

Ne tür riskleri kabul edeceğinize ve verileri ne kadar iyi bildiğinize ve güvendiğinize bağlı olarak, basit değişken enterpolasyonunu kullanabilirsiniz.

$: x="
    this
    is
       variably indented
    stuff
   "
$: echo "$x" # preserves the newlines and spacing

    this
    is
       variably indented
    stuff

$: echo $x # no quotes, stacks it "neatly" with minimal spacing
this is variably indented stuff

-2

Bu muhtemelen sorunuza gerçekten cevap vermiyor, ancak yine de yararlı olabilir.

İlk komut, ikinci komut tarafından görüntülenen komut dosyasını oluşturur.

Üçüncü komut bu komut dosyasını yürütülebilir hale getirir.

Dördüncü komut bir kullanım örneği sağlar.

john@malkovich:~/tmp/so$ echo $'#!/usr/bin/env python\nimport textwrap, sys\n\ndef bash_dedent(text):\n    """Dedent all but the first line in the passed `text`."""\n    try:\n        first, rest = text.split("\\n", 1)\n        return "\\n".join([first, textwrap.dedent(rest)])\n    except ValueError:\n        return text  # single-line string\n\nprint bash_dedent(sys.argv[1])'  > bash_dedent
john@malkovich:~/tmp/so$ cat bash_dedent 
#!/usr/bin/env python
import textwrap, sys

def bash_dedent(text):
    """Dedent all but the first line in the passed `text`."""
    try:
        first, rest = text.split("\n", 1)
        return "\n".join([first, textwrap.dedent(rest)])
    except ValueError:
        return text  # single-line string

print bash_dedent(sys.argv[1])
john@malkovich:~/tmp/so$ chmod a+x bash_dedent
john@malkovich:~/tmp/so$ echo "$(./bash_dedent "first line
>     second line
>     third line")"
first line
second line
third line

Bu komut dosyasını gerçekten kullanmak istiyorsanız, çalıştırılabilir komut dosyasını yolunuzda ~/binolacak şekilde taşımak daha mantıklıdır .

Nasıl textwrap.dedentçalıştığına dair ayrıntılar için python referansına bakın .

Kullanımı $'...'veya "$(...)"sizin için kafa karıştırıcıysa, başka bir soru (her yapı için bir tane) sorun. Bulduğunuz / sorduğunuz soruya bir bağlantı sağlamak güzel olabilir, böylece diğer kişilerin bağlantılı bir referansı olur.


6
İyi niyetli ve hatta muhtemelen yararlı olsa da, OP temel bash sözdizimi hakkında tavsiye istedi ve ona OO paradigmaları, olağanüstü akış kontrolü ve ithalatı kullanan bir python işlevi tanımı verdiniz. Ayrıca, çalıştırılabilir bir dize enterpolasyonunun bir parçası olarak adlandırdınız - bu tür bir soru soran bir kişinin kesinlikle bash'da görmeyeceği bir şey.
Part Atışı
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.