Archのpacman.confファイルでリポジトリソースの追加を自動化しようとしていますが、シェルスクリプトでecho
コマンドを使用しています。ただし、次のように失敗します。
Sudo echo "[archlinuxfr]" >> /etc/pacman.conf
Sudo echo "Server = http://repo.archlinux.fr/\$Arch" >> /etc/pacman.conf
Sudo echo " " >> /etc/pacman.conf
-bash: /etc/pacman.conf: Permission denied
Vimを使用して/etc/pacman.confを手動で変更した場合、
Sudo vim /etc/pacman.conf
:wq
でvimを終了すると、すべてが正常に機能し、pacman.confが「Permission denied」という苦情なしに手動で更新されました。
これはなぜですか? Sudo echo
を機能させるにはどうすればよいですか? (ところで、私はSudo cat
も使用しようとしましたが、アクセス許可も拒否されて失敗しました)
問題は、リダイレクトがSudo
ではなく、元のシェルによって処理されていることです。シェルは心を読み取ることができず、特定の>>
がSudo
を対象としており、それを目的としていないことを知りません。
必要がある:
Sudo)
に渡されますSudo -s
(したがって、Sudo
はシェルを使用して引用されたリダイレクトを処理します。)@geekosaurが説明したように、シェルはコマンドを実行する前にリダイレクトを行います。これを入力すると:
Sudo foo >/some/file
現在のシェルプロセスは、最初に/some/file
を開いて書き込みを試み、それからそのファイル記述子を標準出力にしてから、Sudo
を実行する自身のコピーを作成します。
許可されている場合(sudoerの設定により、実行中のシェルが除外されることがよくあります)、次のようなことができます。
Sudo bash -c 'foo >/some/file'
しかし、一般的に良い解決策は、| Sudo tee
の代わりに>
と| Sudo tee -a
の代わりに>>
を使用することです。これは、リダイレクトが最初にSudo
を必要とする唯一の理由である場合に特に役立ちます。結局、rootとして不必要に実行されるプロセスは、まさに回避するために作成されたSudo
です。そして、echo
をrootとして実行するのは馬鹿げています。
echo '[archlinuxfr]' | Sudo tee -a /etc/pacman.conf >/dev/null
echo 'Server = http://repo.archlinux.fr/$Arch' | Sudo tee -a /etc/pacman.conf >/dev/null
echo ' ' | Sudo tee -a /etc/pacman.conf >/dev/null
最後に> /dev/null
を追加しました。tee
がその出力をboth名前付きファイルに送信しますand独自の標準出力であり、私の端末で見る必要があります。 (tee
コマンドは、その名前を取得する物理パイプラインの「T」コネクタのように機能します。)そして、単一引用符に切り替えました('
...'
)ダブル("
..."
)の代わりに、すべてがリテラルであり、$
の$Arch
の前にバックスラッシュを置く必要はありませんでした。
そのため、Sudo
を使用して、rootとしてファイルに書き込みます。さて、改行を含むテキストをシェルスクリプトで出力する方法についての長い余談です。 :)
最初に、すべてのecho
をサブシェルにグループ化するだけでよいので、リダイレクトを1回行うだけで済みます。
(echo '[archlinuxfr]
echo 'Server = http://repo.archlinux.fr/$Arch'
echo ' ') | Sudo tee -a /etc/pacman.conf >/dev/null
または、printf
の代わりにecho
を使用して、\n
を使用して文字列に改行を直接埋め込むことができます。
printf '[archlinuxfr]\nServer = http://repo.archlinux.fr/$Arch\n ' |
Sudo tee -a /etc/pacman.conf >/dev/null
bash
では、echo -e
で同じ結果を得ることができます:
# BASH ONLY - NOT RECOMMENDED
echo -e '[archlinuxfr]\nServer = http://repo.archlinux.fr/$Arch\n ' |
Sudo tee -a /etc/pacman.conf >/dev/null
ただし、ほとんどのシェルは、試してみると-e
を出力するだけなので、お勧めしません。
printf
とecho -e
の両方を使用すると、コマンドが引数文字列として取得するものには、\n
と入力する場所にリテラルバックスラッシュとそれに続くリテラルNが含まれ、コマンドプログラム次第です( printf
またはecho
)内のコードは、それを改行に変換します。最近の多くのシェルでは、ANSI引用符$'
...'
を使用するオプションがあります。これは、コマンドの前に\n
などのシーケンスをliteral改行に変換しますプログラムは文字列を見ます。つまり、そのような文字列はどのコマンドでも動作します。
echo $'[archlinuxfr]\nServer = http://repo.archlinux.fr/$Arch\n ' |
Sudo tee -a /etc/pacman.conf >/dev/null
しかし、echo -e
より移植性が高い一方で、ANSI引用符は依然として非POSIX拡張機能です。
これを行うための好ましい方法は、ヒアドキュメントを使用し、echo
またはprintf
の必要性を完全に回避することです。
Sudo tee -a /etc/pacman.conf >/dev/null <<'EOF'
[archlinuxfr]
Server = http://repo.archlinux.fr/$Arch
EOF
http://www.innovationsts.com/blog/?p=2758
上記の手順はそれほど明確ではないので、私はそのブログ投稿の手順を使用しています。例があるので、何をする必要があるかが簡単にわかります。
$ Sudo cat /root/example.txt | gzip> /root/example.gz
-bash:/root/example.gz:許可が拒否されました
エラーの原因はパイプラインの2番目のコマンド(gzipコマンド)であることに注意してください。そこで、bashと-cオプションを使用する手法が登場します。
$ Sudo bash -c 'cat /root/example.txt | gzip> /root/example.gz '
$ Sudo ls /root/example.gz
/root/example.gz
Lsコマンドの出力から、圧縮ファイルの作成が成功したことがわかります。
2番目の方法は、コマンド文字列をbashに渡すという点で最初の方法と似ていますが、Sudoを介してパイプラインで実行しています。
$ Sudo rm /root/example.gz
$ echo "cat /root/example.txt | gzip> /root/example.gz" |須藤バッシュ
$ Sudo ls /root/example.gz
/root/example.gz
Sudo bash -c 'echo "[archlinuxfr]" >> /etc/pacman.conf'
ステップ1 bashファイルに関数を作成します(write_pacman.sh
)
#!/bin/bash
function write_pacman {
tee -a /etc/pacman.conf > /dev/null << 'EOF'
[archlinuxfr]
Server = http://repo.archlinux.fr/\$Arch
EOF
}
'EOF'
は解釈しません$Arch
変数。
STE2ソースbashファイル
$ source write_pacman.sh
ステップ関数を実行する
$ write_pacman