シェルスクリプトでShiftを使用する目的は何ですか?

シェルスクリプトでShiftを使用する目的は何ですか?

私は次のスクリプトを見つけました。

#! /bin/bash                                                                                                                                                                                           

if (( $# < 3 )); then
  echo "$0 old_string new_string file [file...]"
  exit 0
else
  ostr="$1"; shift
  nstr="$1"; shift  
fi

echo "Replacing \"$ostr\" with \"$nstr\""
for file in $@; do
  if [ -f $file ]; then
    echo "Working with: $file"
    eval "sed 's/"$ostr"/"$nstr"/g' $file" > $file.tmp 
    mv $file.tmp $file
  fi  
done

彼らが使う線の意味は何ですかshift?スクリプトは少なくともパラメータで使用する必要があると思いますが…?

答え1

shiftbashパラメータリストの先頭からパラメータを削除する組み込み関数。スクリプトに提供された3つの引数が$1、で$2使用できると仮定すると、$3呼び出しはnewをshift 生成します。 Aは2だけ新しいoldに変換されます。詳しくはこちらをご覧ください。$2$1shift 2$1$3

答え2

Goldilocksのコメントとヒューマンリファレンスで説明されているように、 位置shiftパラメータ(など)を再割り当てして、背面の以前の値を取得します。*   以前の値は破棄されます。 (変更されていません。)これを行ういくつかの理由は次のとおりです。$1$2$1$2$2$3$1$0

  • 10番目のパラメータ(存在する場合)に簡単にアクセスできます。動作しません。 aに関連付けられている$10と解釈されます(したがって、同様の結果が生成される可能性があります)。 a次の10番目のパラメータはになります。 (ただし、ほとんどの最新のシェルでは使用できます。)$10Hello0shift$9${10}
  • 〜のようにBash初心者ガイドパラメータを繰り返すために使用できることが証明されています。 IMNSHO、これは素朴ですfor
  • サンプルスクリプトと同様に、いくつかのパラメータを除くすべてのパラメータを同じ方法で簡単に処理できます。たとえば、スクリプトでは、およびは $1テキスト$2文字列、$3他のすべてのパラメータはファイル名です。

結果は次のとおりです。スクリプトが呼び出され、Patryk_script呼び出されるとします。

Patryk_script USSR Russia Treaty1 Atlas2 Pravda3

スクリプトは見る

$1 = USSR
$2 = Russia
$3 = Treaty1
$4 = Atlas2
$5 = Pravda3

このステートメントはostr="$1"変数ostrをに設定しますUSSR。最初のshiftステートメントは、位置パラメーターを次のように変更します。

$1 = Russia
$2 = Treaty1
$3 = Atlas2
$4 = Pravda3

このステートメントはnstr="$1"変数nstrをに設定しますRussia。 2番目のshiftステートメントは、位置パラメータを次のように変更します。

$1 = Treaty1
$2 = Atlas2
$3 = Pravda3

その後、ループはファイルの()をfor()に変更します。USSR$ostrRussia$nstrTreaty1Atlas2Pravda3



スクリプトにはいくつかの問題があります。

  1. $@ のファイルについては、次のようにします。

    スクリプトが次のように呼び出される場合

    Patryk_script ソビエトロシア条約1「World Atlas 2」 Pravda 3

    それを見る

    1 USD = ソ連
    2ドル=ロシア
    $3 = 条約 1
    $ 4 =ワールドアトラス2
    $5 = プラウダ 3

    しかし、$@空白はWorld Atlas2引用されていないので引用されず、ループforは、、、Treaty1および4つのファイルがあると思います。これはおそらくWorldAtlas2Pravda3

    「$@」にあるファイルの場合は、次のようにします。

    (引数に特殊文字を引用してください)または単に

    ファイルの場合

    (より長いバージョンと同じ)

  2. eval "sed's/"$ostr"/"$nstr"/g' $file"

    これをに設定する必要はなく、eval未確認のユーザー入力をに渡すのはeval危険です。たとえば、スクリプトが次のように呼び出されると

    Patryk_script "'; rm *;'" ロシア条約 1 Atlas2 Pravda3

    それが行われますrm *!たとえば、sudoWebインターフェイスを介してスクリプトを実行または呼び出すことができる場合、スクリプトを呼び出すユーザーよりも高い権限で実行できる場合、これは大きな問題です。ディレクトリで直接使用する場合は、それほど重要ではないかもしれません。ただし、次のように変更されることがあります。

    sed "s/$ostr/$nstr/g" "$file"

    それでもやや危険がありますが、それほど危険ではありません。

  3. if [ -f $file ]> $file.tmpおよびは、スペース(またはその他の興味深い文字)を含めることができるファイル名を処理するためにそれぞれ、およびでなければmv $file.tmp $file なりません。 (このコマンドはスペースを含むファイル名も削除します。)if [ -f "$file" ]> "$file.tmp"mv "$file.tmp" "$file"eval "sed …


* shiftオプションの引数を取ります。移動する引数の数を指定する正の整数。デフォルト値は1(1)です。たとえば、になる原因shift 4などがあります。 (例で参考にしてください。$5$1$6$2Bash初心者ガイドそれは間違っています。 )スクリプトは次のように変更できます。

ostr="$1"
nstr="$2"
shift 2

これがより明確であると見ることができます。



アメリカ/警告する:

Windowsのコマンドプロンプト(バッチファイル)言語は、デフォルトでSHIFTUnixシェルのコマンドと同じ操作を実行するコマンドもサポートしていますshiftが、人々が混乱しないように隠す重要な違いが1つあります。

  • このコマンドSHIFT 4はエラーであり、「SHIFTコマンドの無効な引数」エラーメッセージが生成されます。
  • SHIFT /n、どこn0 ~ 8 の整数で、有効ですが移動されません。n 移流。一度変身して、から始まるこれN 番目のパラメータです。したがってSHIFT /4 結果%5(5番目のパラメータ)はとなり%4,  %6%5このようにしてパラメータ0~3だけ残ります。

答え3

最も簡単な説明はこれです。次のコマンドを検討してください。

/bin/command.sh SET location Cebu
/bin/command.sh SET location Cebu, Philippines 6014 

ヘルプがないと、shift値がランダムに長くなる可能性があるため、場所の値全体を抽出することはできません。 2回移動すると、argsと次のようにSET削除locationされます。

x="$@"
echo "location = $x"

$@そのものを長く見つめてください。これはx、スペースとコンマが含まれていても、場所全体を変数に保存できることを意味します。つまり、shift変数に残っている値を呼び出して検索します$@

修正する 以下に、概念と使用法を示す非常に短いコードスニペットを追加しました。shiftこれがなければ、フィールドを正しく抽出するのは非常に難しいでしょう。

#!/bin/sh
#

[ $# -eq 0 ] && return 0

a=$1
shift
b=$@
echo $a
[ -n "$b" ] && echo $b

説明する:以後shift、可変第二スペースなどに関係なく、配信された残りのコンテンツを含める必要があります。これは[ -n "$b" ] && echo $b保護装置です。私たちは印刷するだけです。第二内容がある場合です。

答え4

shiftコマンドライン引数を呼び出すたびに、要素が表示されるFIFOキューとして扱われます。

array = [a, b, c]
shift equivalent to
array.popleft
[b, c]
$1, $2,$3 can be interpreted as index of the array.
$# is the length of array

関連情報