printfが予想よりも多くの引数を印刷するのはなぜですか?

printfが予想よりも多くの引数を印刷するのはなぜですか?

このシェルスクリプトはなぜ入力を2回印刷するのですか?

スクリプトは5以降の入力を無視すると予想しました。

スクリプト:

#! /bin/bash
echo "Enter 5 words : "
read  a b c d e 
printf "> %s %s %s %s %s <" $a $b $c $d $e

出力:

user@linux:~$ pico ifs2.sh
user@linux:~$ ./ifs2.sh
Enter 5 words : 
1 2 3 4 5 
> 1 2 3 4 5 <user@linux:~$ ./ifs2.sh
Enter 5 words : 
1 2 3 4 5 6
> 1 2 3 4 5 <> 6     <user@linux:~$ ./ifs2.sh
Enter 5 words : 
1 2 3 4 5 6 7 8 9 0
> 1 2 3 4 5 <> 6 7 8 9 0 <user@linux:~$ 

さらに、次のスクリプトは$ IFS設定に関係なく機能します。なぜ?

#! /bin/bash    
old="$IFS"
IFS=":"
echo "IFS = $IFS"
echo "Enter 5 words : "
read  a b c d e 
printf "> %s %s %s %s %s <" $a $b $c $d $e    
IFS="$old"

出力:

user@linux:~$ ./ifs2.sh
IFS = :
Enter 5 words : 
1 2 3 4 5  
> 1 2 3 4 5      <user@linux:~$ ./ifs2.sh
IFS = :
Enter 5 words : 
1 2 3 4 5
> 1 2 3 4 5     <user@linux:~$ ./ifs2.sh
IFS = :
Enter 5 words : 
1:2:3:4:5
> 1 2 3 4 5 <user@linux:~$ 

答え1

3つの質問があります。

  1. そしてread、変数名が入力フィールドより小さい場合、最後の変数は区切り文字を使用して行の残りのすべてのフィールドにバインドされます。これは、これが予期しない最初の例に$e現れることを意味します。5 6
  2. すべて$a..$e参照されていないため、その値は変更されます。フィールド分割$e" 5 6"を押し続けると、次に展開されます。二つコマンドのパラメーターです。
  3. printf%置き換える引数と同じように、一度に多くの引数を繰り返し使用してすべての引数を使用します。これは文書に埋め込まれたように:

    formatオペランドは、パラメータオペランドを満たすために必要な回数だけ再利用する必要があります。追加cまたはs変換指定子は、空の文字列引数が指定されているかのように評価されます。その他の追加変換仕様は、ゼロ引数が与えられたかのように評価されます。

    つまり、未使用のパラメータがある場合は、フォーマット文字列全体を含めて最初からやり直して処理します。これは配列全体をフォーマットする場合に便利です。たとえば、次のようになります。

    printf '%b ' "${array[@]}"
    

    あなたのprintfコマンドは$a各..に1つのパラメータを取り、..$dに多くのパラメータが残ります$e$e""の場合、2つのループが5 6あり、printf2番目の6フォーマットが開始されます。それが出たとき、5 6 7 8 9 102番目の印刷のために完全に交換されました。


追加の仮想フィールドを追加してパラメータの置き換えを参照すると、これらすべてのread状況を回避できます(常に良い考えです)。

read  a b c d e dummy
printf "> %s %s %s %s %s <" "$a" "$b" "$c" "$d" "$e"

これにより、以下が提供されます。

Enter 5 words : 
1 2 3 4 5 6 7 8 9 10
> 1 2 3 4 5 <

dummyすべての追加フィールドとprintf予想される5つのパラメータのみを取得します。


2番目の編集質問にも同様の答えがあります。a空白がない場合にのみ値を取得します。これは..これは何も拡張されないことをIFS意味するので、引数は1つしか得られません。型文字列にスペースを置き換えずに印刷します(「空の文字列引数が指定されているかのように」)。$b$eprintf

答え2

 printf "> %s < " 1 2 3

印刷する

 > 1 <> 2 <> 3 <

  printf "> %s %s <" 1 2 3

印刷

 > 1 2 <> 3  <

printfフォーマット文字列を満たすためにすべての引数を食べてから、すべての引数が処理されるまで繰り返します。

2番目のスクリプトは、$aコマンドが別の反復で漏洩しないようにのみ割り当てられているために機能します(繰り返しは1つのみです)。


この動作は提供されたテキストで説明されていますhelp printf

...すべての引数を使用するために必要に応じてフォーマットが再利用されます。書式に必要な数より引数が少ない場合、追加の書式指定は、適切なゼロ値または空の文字列が指定されたかのように動作します。 ...

によって承認され、http://pubs.opengroup.org/onlinepubs/9699919799/utilities/printf.html

関連情報