62430

[code]

    echo -e "\nexport PYENV_ROOT=$PYENV" | sudo tee -a ~/.bash_profile  >> /dev/null
    
[/code]

というシェルスクリプトの書き方を見かけたのですが

[code]

    echo "\nexport PYENV_ROOT=$PYENV" >> ~/.bash_profile
    
[/code]

と何か違いがあるのでしょうか

tee -a コマンド  
自分が所持してるに決まってる .bash_profile に sudo をつける意図

の２点がよくわからないのですが説明していただけるとありがたいです

.bash_profile が存在しなかった場合  
.bash_profile が作成され所有者は実行ユーザではなく  
root で作成されてしまうのでかえってまずい結果になりそうな気がします

単なるミスなのかこういう書き方をすることでメリットや慣習があれのか知りたいです


CC BY-SA 4.0
2020-01-21T09:49:17.393
62428
2020-01-21T13:51:34.873
2020-01-21T12:07:53.313
19110
question
shellscript
シェルスクリプトでteeを使ってファイル追記する書き方について


# Solaris 10のshの場合

`tee -a ファイル`と`>>ファイル`は次の点で結果が変わることがあります。

  * `tee -a`はファイルを`O_APPEND`で`open`して`write`する。
  * `>>ファイル`はファイルの末尾に`lseek`して`write`する。

あるプロセスが`>>ファイル`を実行しているとき、`lseek`と`write`の間で、別のプロセスが割り込んで同じファイルに対して`>>ファイル`を実行すると、２つのプロセスの`write`結果が混ざってしまうことがあります。

shに依存する振る舞いかもしれませんが、`Solaris 10`のshではそうでした。  
※ shスクリプトでログ出力していたときに、ログファイルが乱れていたので、その原因を調べた結果です。

Solaris10の環境が残っていたので`/bin/sh`の振る舞いを`truss`で確認しました。ファイルの末尾にシークしています。

[![trussの結果](https://i.stack.imgur.com/cTRpG.jpg)](https://i.stack.imgur.com/cTRpG.jpg)

なお、`/bin/bash`では`O_APPEND`で`open`していました。

* * *

# bashでの結果

centosでもbashの振る舞いを確認してみました。  
結果は`Bourne Shell`のときと違っており、リダイレクト先のファイルを`O_APPEND`で`open`していました。

**スクリプト**

[code]

    #!/bin/bash
    echo "AAA" >> ./log
    
[/code]

**straceの結果**

[code]

    openat(AT_FDCWD, "./log", O_WRONLY|O_CREAT|O_APPEND, 0666) = 3
    fcntl(1, F_GETFD)                       = 0
    fcntl(1, F_DUPFD, 10)                   = 10
    fcntl(1, F_GETFD)                       = 0
    fcntl(10, F_SETFD, FD_CLOEXEC)          = 0
    dup2(3, 1)                              = 1
    close(3)                                = 0
    fstat(1, {st_mode=S_IFREG|0664, st_size=8, ...}) = 0
    write(1, "AAA\n", 4)                    = 4
    
[/code]

この結果は、`GNU bash, バージョン 4.4.20`のものです。

**確認したbashのバージョン**

`GNU bash, バージョン 4.4.20(1)-release (x86_64-pc-linux-gnu)`

Solaris10で確認したときのバージョンは以下です。  
`GNU bash, バージョン 3.2.51(1)-release (i386-pc-solaris2.10)`


CC BY-SA 4.0
2020-01-21T10:23:28.397
62429
2020-01-21T13:51:34.873
2020-01-21T13:51:34.873
35558
35558
62428
answer


## echo -e

echo コマンドは外部コマンドかシェルの内部コマンドか、また内部コマンドでもシェルの種類によって動作が違うので、`man echo`
では動作の詳細がわからない事が有ります。  
今回の場合はおそらく bash の内部コマンドの echo の動作だと思うので、`man bash` で調べる必要が有ります。

bash のマニュアルでの echo の説明には以下のように書かれています。

> If the -e option is given, interpretation of the following backslash-escaped
> characters is enabled.  
>  ～略～  
>  \n new line

つまり `-e` を付けると `\n` が改行に変換されて出力されるという事です。逆に `-e` を付けないと '\n' がそのまま出力されます。

## tee -a

`tee -a` は標準入力から読んだ内容をファイルに追加すると同時に標準出力にも出力するコマンドですが、標準出力は /dev/null
にリダイレクトして捨てているので、単純にファイルに追記するコマンドとして利用しています。  
これだけだと `>>` で追記するのと違いが判りづらいですが、今回の場合は `sudo` と組み合わせている事に意味があります。

`echo -e "hoge" | sudo tee -a ~/.profile >> /dev/null` の場合は `tee`
がroot権限で起動されてファイルに追記します。  
一方 `sudo echo "hoge" >> ~/.profile` の場合は、echo
コマンドがroot権限で起動されますが、その出力をリダイレクトでファイルに書き込む(出力先を~/.profileにする)のはシェルが行う為、`sudo`による権限昇格の影響を受けません。


CC BY-SA 4.0
2020-01-21T10:58:03.760
62430
2020-01-21T10:58:03.760
12203
62428
answer