Shebang'da “/ usr / bin / env sed -f” kullanmanın yolu?


Yanıtlar:


33

Portatif olarak, bir #!satıra birden fazla argüman koyamazsınız . Bu, yalnızca tam yol ve bir argüman (örneğin #!/bin/sed -fveya #!/usr/bin/sed -f) veya #!/usr/bin/envtercümana hiçbir argüman olmadığı anlamına gelir .

Taşınabilir bir komut dosyası almak için geçici bir çözüm #!/bin/sh, sed komut dosyasını komut satırı argümanı olarak geçen bir kabuk sarmalayıcı kullanmaktır . Bunun POSIX tarafından onaylanmadığına dikkat edin (çok amaçlı komut dosyaları -e, taşınabilirlik için her komut için ayrı bir argümanla yazılmalıdır ), ancak birçok uygulamada çalıştığını unutmayın.

#!/bin/sh
exec sed '
s/a/b/
' "$@"

Uzun bir senaryo için, heredoc kullanmak daha uygun olabilir. Heredoc'un bir avantajı, eğer varsa, içindeki tek alıntıları alıntılamanıza gerek kalmamasıdır. Büyük bir dezavantajı, senaryonun standart girişinden başlayarak iki can sıkıcı sonuçla beslenmesidir. Bazı sed sürümleri -f /dev/stdinbunun yerine gerektirir -f -, bu da taşınabilirlik için bir problemdir. Daha da kötüsü, komut dosyası bir filtre işlevi göremez, çünkü standart girdi komut dosyasıdır ve veri olamaz.

#!/bin/sh
exec sed -f - -- "$@" <<'EOF'
s/a/b/
EOF

Heredokun dezavantajı, faydalı bir kullanımı ile giderilebilir cat. Bu, komut dosyasının tamamını komut satırına yeniden koyduğundan, POSIX uyumlu değil, pratikte büyük ölçüde taşınabilir.

#!/bin/sh
exec sed "$(cat <<'EOF')" -- "$@"
s/a/b/
EOF

Başka bir geçici çözüm, hem sh hem de sed tarafından ayrıştırılabilecek bir komut dosyası yazmaktır. Bu taşınabilir, oldukça verimli, sadece biraz çirkin.

#! /bin/sh
b ()
{
x
}
i\
f true; then exec sed -f "$0" "$@"; fi
: ()
# sed script starts here
s/a/b/

açıklamalar:

  • Sh altında: denilen işlevi tanımlayın b; içerik, sözdizimi açısından iyi biçimlendirilmiş olduğu sürece önemli değildir (özellikle boş bir işleve sahip olamazsınız). Sonra doğruysa (yani her zaman), sedkomut dosyası üzerinde yürütün .
  • Sed altında: ()etikete dallanır , daha sonra bazı iyi biçimli girdiler. Ardından ietkisi olmayan bir komut, çünkü her zaman atlanır. Sonunda ()etiketin ardından betiğin yararlı kısmı var.
  • GNU sed, BusyBox ve OpenBSD altında test edilmiştir. (GNU sed'de daha basit bir şeyle kurtulabilirsiniz, ancak OpenBSD sed, atladığı parçalar konusunda seçicidir.)

1
"ya da #!/usr/bin/envtartışma yok." çok iyi ifade değil. Belki de "ya da #!/usr/bin/env sedve sed 'e argüman yok."
cjm

"Sadece biraz çirkin" ve iki dilli komut dosyası için +1 :)
çekilme

6

İşletim sistemine bağlı olarak shebang'ın (#!) Çeşitli uyumsuz uygulamaları vardır. Bazıları tam bir argüman listesi oluşturuyor, bazıları komut yolunu koruyor ve kalan tüm argümanları tek bir taneye koyuyor, bazıları tüm argümanları yok sayıyor ve yalnızca komut yolunu geçiyor ve son olarak da bazıları tüm dizeyi tek bir satır olarak geçiriyor komut. İkinci durumda görünüyorsun.


2

env, "sed -f" isimli bir dosyayı bulmaya çalışıyor. Shebang hattınız olarak "#! / Usr / bin / sed -f" yi deneyebilirsiniz.


2

GNU coreutils v8.30'dan itibaren şunları yapabilirsiniz:

#!/usr/bin/env -S sed -f

Bu özellik son (2018-04-20) ilave edildi işlemek için env.ceklenen GNU coreutils ambalajlarda, -Sveya --split-stringseçenek.

Gönderen envadam sayfası:

OPTIONS
-S/--split-string usage in scripts
    The  -S  option allows specifing multiple parameters in a script.
    Running a script named 1.pl containing the following first line:

            #!/usr/bin/env -S perl -w -T

    Will execute perl -w -T 1.pl .

    Without the '-S' parameter the script will likely fail with:

            /usr/bin/env: 'perl -w -T': No such file or directory

    See the full documentation for more details.

GNU coreutils kılavuzunda daha fazla örnek mevcuttur .

-vAyrıntılı çıktı seçeneğini de kullanırsanız, envbağımsız değişkenlerin dizesini tam olarak nasıl bölebildiğini görebilirsiniz :

İçinde my_sed_script.sed:

#!/usr/bin/env -vS sed -f
s/a/b/

Yürütme:

$ ./my_sed_script.sed
split -S:  ‘sed -f’
 into:    ‘sed’
     &    ‘-f’
executing: sed
   arg[0]= ‘sed’
   arg[1]= ‘-f’
   arg[2]= ‘./my_sed_script.sed’

Not: Bu yalnızca /usr/bin/env, --split-stringözellikle GNU’nun bir özelliği olduğu için kullanan shebanglar için geçerlidir env.


1

Bu cevap zarif bir çözüme giden bir yol sunar: /programming//a/1655389/642372

  1. read bir kabuk değişkenine heredok.
  2. Bu değişkeni konumsal bir argüman olarak iletin sed.

Numune:

#!/usr/bin/env bash

read -rd '' SED_SCRIPT <<EOD      
# Your sed script goes here.
s/a/b/
EOD

exec sed "$SED_SCRIPT" "$@"

1

Walker'in çözümünü severim, ancak iyileştirilebilir (yorumlar ayrı biçimlendirilmiş metni kabul etmediği için bunu ayrı bir cevaba koyun). Bu Linux veya Bash'in tüm sürümlerinde çalışmayabilir, ancak Ubuntu 17.10'da bunu aşağıdakine kesebilirsiniz:

#!/usr/bin/env bash
read SED_SCRIPT <<EOD
s/a/b/
EOD
sed "$SED_SCRIPT" "$@"

Komutu kaldırabilir evalve basitleştirebilirsiniz read, ancak heredoc içindeki yorumdan kurtulmanız gerekir.

Ayrıca, sed hakkında bilmek istediğiniz ancak sormaktan korktuğunuz her şey için, http://www.grymoire.com/unix/sed.html adresinde çok faydalı bir eğitim var . Bu kaybetme pahasına, daha iyi bir çözüm önerir /usr/bin/envve yolu sabit kodlama sed:

#!/bin/sed -f
s/a/b/
s/c/d/

Bu, birden fazla s///değişimin desteklenmesinin ilave avantajına sahiptir .

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.