このスクリプトが端末では機能するのにファイルでは機能しないのはなぜですか?


18

このシェルスクリプトをファイルに保存しました。基本的な文字列の置換を行います。

#!/bin/sh
html_file=$1
echo "html_file = $html_file"
substr=.pdf
pdf_file="${html_file/.html/.pdf}"
echo "pdf_file = $pdf_file"

コマンドラインに貼り付けると、正常に機能します。

$ html_file="/home/max/for_pauld/test_no_base64.html"
  echo "html_file = $html_file"
  substr=.pdf
  pdf_file="${html_file/.html/.pdf}"
  echo "pdf_file = $pdf_file"

与える

html_file = /home/max/for_pauld/test_no_base64.html
pdf_file = /home/max/for_pauld/test_no_base64.pdf

これが上記のechoの出力です-意図したとおりに機能しています。

しかし、スクリプトを呼び出すと、

$ saucer "/home/max/for_pauld/test_no_base64.html"

私はこの出力を取得します:

html_file = /home/max/for_pauld/test_no_base64.html
/home/max/bin/saucer: 5: /home/max/bin/saucer: Bad substitution

私のスクリプトは別のバージョンのbashなどを使用していますか?シバンのラインを変更する必要がありますか?


6
そのパラメーター展開は、bashism(まあ、非POSIX)です。
-jasonwryan

ありがとう!うまくいきました。私は違いのビットかすんだと思うshbash。読み上げます。あなたのコメントを答えにするのが面倒なら、私はそれを正しいとマークします。
マックスウィリアムズ

デュークに詳細な答えをくれたが、とにかく感謝する。
マックスウィリアムズ

2
@MaxWilliams:簡単に言えば、shは元のボーンシェルです。互換性のあるすべてのスクリプトは、sh用に作成する必要があります。しかし、その後のシェル(例:bash、Bourne Againシェル)の多くは「ほぼ互換」であり、多くの特別な機能が追加されています。使用した置換など。最近では、posix機能のみを使用して非常に安全ですが、移植性はより狭いセット(つまりshのみ)に依存することに注意してください。したがって、一般的には、次のように使用#!/usr/bin/env bashします。あなたのシバンとして、そして必要に応じて、posixlyに定義された置換を使用しますが、移植性の警告があります。そして読む:unix.stackexchange.com/a/48787/27616
オリビエデュラック

回答:


36

shとは

sh(またはシェルコマンド言語)は、POSIX標準で記述されたプログラミング言語です。それは多くの実装を持っています(ksh88dash、...)。bashの実装と考えることもできますsh(以下を参照)。

のでsh仕様ではなく、実装され、/bin/shほとんどのPOSIXシステム上の実際の実装へのシンボリックリンク(またはハードリンク)です。

バッシュとは

bashsh互換性のある実装として開始されました(ただし、POSIX標準よりも数年前に作成されました)が、時間が経つにつれて多くの拡張機能を取得しました。これらの拡張機能の多くは、有効なPOSIXシェルスクリプトの動作を変更する可能性があるため、それ自体bashは有効なPOSIXシェルではありません。むしろ、POSIXシェル言語の方言です。

bash--posixスイッチをサポートしているため、よりPOSIX準拠になります。また、として呼び出されshた場合、POSIXを模倣しようとします。

sh = bash?

長い間、ほとんどのGNU / Linuxシステムで/bin/sh使用されてい/bin/bashました。その結果、この2つの違いを無視することはほぼ安全になりました。しかし、それは最近変わり始めました。

/bin/sh指し示していない/bin/bash(および存在しないシステムもある)システムの一般的な例を次に示します/bin/bash

  1. シンボリックリンク近代DebianとUbuntuのシステムshdashデフォルトでは、
  2. Busyboxは、通常、Linuxシステムのブート時にの一部として実行されますinitramfsashシェル実装を使用します。
  3. BSD、および一般に非Linuxシステム。OpenBSDはpdksh、Kornシェルの子孫であるを使用します。FreeBSD shは、元のUNIX Bourneシェルの子孫です。Solarisには独自の機能がshあり、長い間POSIXに準拠していませんでした。Heirloomプロジェクトから無料の実装を入手できます。

/bin/shシステム上のどのポイントを見つけることができますか?

複雑なのは/bin/sh、シンボリックリンクまたはハードリンクである可能性があることです。シンボリックリンクの場合、それを解決するポータブルな方法は次のとおりです。

% file -h /bin/sh
/bin/sh: symbolic link to bash

ハードリンクの場合は、試してください

% find -L /bin -samefile /bin/sh
/bin/sh
/bin/bash

実際には、-Lフラグは、シンボリックリンクとハードリンクの両方をカバーしますが、この方法の欠点は、移植性がないということである- POSIXは必要ありません findサポートするために-samefile、両方が、オプションをGNUは見つけるFreeBSDが見つけ、それをサポートしています。

シバンライン

最終的に、«shebang»の行を書くことによって、どれを使用するかを決めるのはあなた次第です。

例えば

#!/bin/sh

sh(そして、それが指すものは何でも)を使用します。

#!/bin/bash

使用/bin/bash可能な場合に使用します(使用できない場合はエラーメッセージで失敗します)。もちろん、別の実装を指定することもできます。例えば

#!/bin/dash

使用するもの

私自身のスクリプトでshは、次の理由で好みです。

  • 標準化されています
  • それははるかにシンプルで簡単に学ぶことができます
  • POSIXシステム間で移植可能—たまに持っていなくてもbash、持っている必要があるsh

使用する利点bashもあります。その機能は、プログラミングをより便利にし、他の最新のプログラミング言語でのプログラミングに似ています。これらには、スコープ付きローカル変数や配列などが含まれます。Plain shは非常に最小限のプログラミング言語です。


詳細な回答をありがとう:DebianベースのLinux Mintを使用して/bin/shおり、実際にはへのシンボリックリンク/bin/dashです。
マックスウィリアムズ

POSIX shに準拠したい場合は、シェバンを完全に除外することをお勧めします。シェルコマンドのファイルの最初の行が文字「#!」で始まる場合、結果は不特定 ですpubs.opengroup.org/onlinepubs/009695399/ユーティリティ/…
ダニエルジュール

4
@DanielJour Unixライクなシステムがシバンの通常のサポートをやめた場合、それは非常に多くのことを壊し、実質的に使用できなくなります。したがって、POSIXで指定されていなくても、事実上の標準です。唯一の実際の互換性の問題は、インタープリターへのパスが異なる場合があることです。
バーマー

23

@ Hunter.S.Thompsonからの優れた答えに加えて、スクリプトの移植性のない部分は

pdf_file="${html_file/.html/.pdf}"

これ${variable/search/replace}はGNU拡張機能です。ただし、純粋なPOSIXを使用すると簡単に回避できます。

pdf_file="${html_file%.html}".pdf

ハンターに続いて、これはシバンを変更するよりも良い修正です #! /bin/bash


ありがとう-私はそれが「より純粋な」修正であることに同意しますが、bashはターミナルで日常的に使用するものであり(デフォルトで)、スクリプトと同じことをする方が簡単ですコマンドライン。
マックスウィリアムズ

1
@MaxWilliamsもちろん、問題ありません。これは主にQ&Aデータベース用でした。
フィリポス
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.