Quantcast
Channel: Bashタグが付けられた新着記事 - Qiita
Viewing all articles
Browse latest Browse all 2872

"${-#*i}" は カレントシェルを変数展開したものだった

$
0
0

事の発端

/etc/profile に以下のような記述がある

for i in /etc/profile.d/*.sh ; do
    if [ -r "$i" ]; then
        if [ "${-#*i}" != "$-" ]; then
            . "$i"
        else
            . "$i" >/dev/null 2>&1
        fi
    fi
done

この "${-#*i}"が何か分からなくて小1時間調べる羽目に...

"${-#*i}" とは

  • 結論、 カレントシェルのフラグ情報が入っているシェル変数を変数展開し、前方一致除去したもの

分解して解釈する

$-または ${-}は カレントシェルが実行された時のオプションが入っている

$ echo "$-"
himBH

このオプションが何かというと(man bash 抜粋)

-h  Remember the location of commands as they are looked up for execution. This is enabled by default.
-i  If the -i option is present, the shell is interactive.
-m  Monitor mode. Job control is enabled. This option is on by default for interactive shells on systems that support it (see JOB CONTROL above). All processes run in a separate process group. When a background job completes, the shell prints a line containing its exit status.
-B  The shell performs brace expansion (see Brace Expansion above). This is on by default.
-H  Enable ! style history substitution. This option is on by default when the shell is interactive.

# は変数展開の前方一致除去

$ x=foobar; echo "${x}"
foobar

$ x=foobar; echo "${x#f}"  // 前方一致で f を除去
oobar

$ x=foobar; echo "${x#foo}" // 前方一致で foo を除去
bar

$ x=foobar; echo "${x#*b}"  // 前方一致で *b を除去(*はワイルドカード)
ar
  • これも man bash に書いてある
       ${parameter#word}
       ${parameter##word}
              Remove matching prefix pattern.  The word is expanded to produce a pattern just as in pathname expansion, and matched against the expanded value of parameter using the rules described under Pattern Matching below.  If  the  pattern  matches  the
              beginning  of the value of parameter, then the result of the expansion is the expanded value of parameter with the shortest matching pattern (the ``#'' case) or the longest matching pattern (the ``##'' case) deleted.  If parameter is @ or *, the
              pattern removal operation is applied to each positional parameter in turn, and the expansion is the resultant list.  If parameter is an array variable subscripted with @ or *, the pattern removal operation is applied to each member of the  array
              in turn, and the expansion is the resultant list.

つまり "${-#*i}" とは

$ echo "${-}"
himBH

$ echo "${-#*i}"
mBH

/etc/profile では何をやりたいのか

  • 再掲
for i in /etc/profile.d/*.sh ; do
    if [ -r "$i" ]; then
        if [ "${-#*i}" != "$-" ]; then
            . "$i"
        else
            . "$i" >/dev/null 2>&1
        fi
    fi
done

if [ "\${-#*i}" != "$-" ]; then

  • カレントシェルが、インタラクティブかどうかを条件としている
  • インタラクティブな場合は true
    • シェルスクリプトを実行
  • インタラクティブではない場合は false
    • シェルスクリプトを実行するが、標準出力は捨てて、標準エラーを標準出力に出すようにしている

. "$i"

  • ちなみに、この .は、カレントシェルのプロセスを置換して、処理を実行する execの省略形である
  • man bash 抜粋
  exec [-cl] [-a name] [command [arguments]]
         If command is specified, it replaces the shell.  No new process is created.  The arguments become the arguments to command.  If the -l option is supplied, the shell places a dash at the beginning of the zeroth argument passed to  command.   This
         is what login(1) does.  The -c option causes command to be executed with an empty environment.  If -a is supplied, the shell passes name as the zeroth argument to the executed command.  If command cannot be executed for some reason, a non-inter-
         active shell exits, unless the execfail shell option is enabled.  In that case, it returns failure.  An interactive shell returns failure if the file cannot be executed.  A subshell exits unconditionally if exec fails.  If command is not  speci-
         fied, any redirections take effect in the current shell, and the return status is 0.  If there is a redirection error, the return status is 1.

Viewing all articles
Browse latest Browse all 2872

Trending Articles