Bashスクリプトとインタラクティブシェルの空白の違い

Bashスクリプトとインタラクティブシェルの空白の違い

なぜこれが起こるのか教えてください。

Linux bashシェルでは:

ps
PID TTY          TIME CMD
20406 pts/0    00:00:01 bash
26896 pts/0    00:00:00 ps

次のコマンドを実行します。

str="a b c d"
printf "%s\n"  ` echo $str `
a
b
c
d

しかし、bashスクリプトでは

#!/bin/bash
.
.
.
.

str="a b c d"
printf "%s\n"  ` echo $str `

次のように印刷されます。

a b c d  

そして、スクリプトの予想結果は次のようになります。

a
b
c
d

私のBashスクリプトで何を見逃していますか? bash ENVやこれに似たものかもしれません。

また、shoptbashスクリプトでコマンドを実行しましたが、結果は次のようになります。

  utocd  off
  cdable_vars  off
  cdspell  off
  checkhash  off
  checkjobs  off
  checkwinsize  off
  cmdhist  on
  compat31  off
  compat32  off
  compat40  off
  compat41  off
  direxpand  off
  dirspell  off
  dotglob  off
  execfail  off
  expand_aliases  off
  extdebug  off
  extglob  off
  extquote  on
  failglob  off
  force_fignore  on
  globstar  off
  gnu_errfmt  off
  histappend  off
  histreedit  off
  histverify  off
  hostcomplete  on
  huponexit  off
  interactive_comments  on
  lastpipe  off
  lithist  off
  login_shell  off
  mailwarn  off
  no_empty_cmd_completion  off
  nocaseglob  off
  nocasematch  off
  nullglob  off
  progcomp  on
  promptvars  on
  restricted_shell  off
  shift_verbose  off
  sourcepath  on
  xpg_echo  off

ベストアンサー1

この動作は、2 つの状況でのみ再現できます。

  1. 二重引用符コマンドの置換:

    #!/bin/bash
    
    str="a b c d"
    printf "%s\n"  "`echo $str`"
    
  2. または、内部フィールド区切り記号(IFS変数)を変更します。たとえば、次のようになります。

    #!/bin/bash
    
    IFS=,
    str="a b c d"
    printf "%s\n" `echo $str`
    

どちらの場合も、出力は次のようになります。

$ ./test.sh
a b c d

最初のケースを変更するには、引用符を削除して復元するには、IFSコマンド置換の上のデフォルト値に設定します。

IFS=$' \t\n'

IFS変更後に出力が変わる理由と二重引用符の共通点が何であるかを少し説明してください。

最後から始めましょう。

printf "%s\n" a b c d

とは大きく違う

printf "%s\n" 'a b c d'

最初のケースでは、4つの別々の単語があり、printfそれを1つずつ出力して新しい行を追加します。第2のケースでは、単語全体がa b c d単一の単語として扱われ、printf端末に直接出力される。二重引用符を追加すると、出力が単一の単語`echo $str`として扱われることが明らかになりました。

IFSそれが始まる場所です。つまり、拡張後に単語を分割するためにttが使用されるため、デフォルトでは式は出力ですが、明示IFS=$' \t\n'的な引用符を使用しなくても - 世界になります。変数なしでこれをより明確に確認できます。echo a b c da b c dIFS=,'a b c d'

$ IFS=,
$ printf "%s\n"  `echo a b c d`
a b c d

$ IFS=$' \t\n'
$ printf "%s\n"  `echo a b c d`
a
b
c
d

$()最後の注意:バックティックの代わりにコマンド置換形式を使用する方が良いですが、これは別のトピックです。

おすすめ記事