95

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

/etc/pacman.confにvimを使用して手動で変更を加えた場合は、

sudo vim /etc/pacman.conf

でvimを終了すると:wq、すべてが正常に機能し、私のpacman.confは「許可が拒否されました」という苦情なしに手動で更新されました。

なんでそうなの?そして、どうすればsudo echo仕事に取り掛かることができますか?(ところで、私も使ってみsudo catましたが、許可が拒否されて失敗しました)

4

6 に答える 6

141

@geekosaurが説明したように、シェルはコマンドを実行する前にリダイレクトを実行します。これを入力すると:

sudo foo >/some/file

現在のシェルプロセスは、最初に書き込み用に開こうとする自身のコピーを作成し/some/file、それが成功すると、そのファイル記述子を標準出力にし、成功した場合にのみ実行しsudoます。これは最初のステップで失敗しています。

許可されている場合(sudoer構成ではシェルの実行が妨げられることがよくあります)、次のようなことができます。

sudo bash -c 'foo >/some/file'

しかし、一般的に良い解決策は、の代わりに、の代わりにを使用する| sudo teeことです。そもそもリダイレクトが必要な唯一の理由である場合、これは特に便利です。結局のところ、rootとしてプロセスを不必要に実行することは、避けるために作成されたものです。そして、rootとして実行するのはばかげています。>| sudo tee -a>>sudosudoecho

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ため、最後に追加しました。端末で表示する必要はありません。(このコマンドは、物理パイプラインの「T」コネクタのように機能し、その名前が付けられます。)そして、すべてがリテラルになるように、二重引用符( ... )ではなく一重引用符( ... )に切り替えました。 inの前にバックスラッシュを置く必要はありませんでした。(引用符または円記号がないと、シェルパラメーターの値に置き換えられます。これはおそらく存在しません。この場合、は何にも置き換えられず、消えてしまいます。)teetee''""$$arch$archarch$arch

つまり、。を使用してrootとしてファイルに書き込むことができますsudo。次に、シェルスクリプトで改行を含むテキストを出力する方法についての長い余談があります。:)

彼らが言うように、それをBLUFするために、私の好ましい解決策は、ヒアドキュメントを上記のsudo teeコマンドにフィードすることです。catその場合、 orechoまたはorprintfまたはその他のコマンドはまったく必要ありません。一重引用符は番兵の紹介に移動しました<<'EOF'が、同じ効果があります。本文は文字通りのテキストとして扱われるため、その$archままにしておきます。

sudo tee -a /etc/pacman.conf >/dev/null <<'EOF'
[archlinuxfr]
Server = http://repo.archlinux.fr/$arch

EOF

しかし、それは私がそれを行う方法ですが、代替手段があります。ここにいくつかあります:

1行に1つずつ固定できますがecho、すべてをサブシェルにグループ化するため、ファイルに追加する必要があるのは1回だけです。

(echo '[archlinuxfr]'
 echo 'Server = http://repo.archlinux.fr/$arch'
 echo ' ') | sudo tee -a /etc/pacman.conf >/dev/null

に追加-eする場合echo(およびその非POSIX拡張機能をサポートするシェルを使用している場合)、次を使用して改行を文字列に直接埋め込むことができます\n

# NON-POSIX - NOT RECOMMENDED
echo -e '[archlinuxfr]\nServer = http://repo.archlinux.fr/$arch\n ' | 
  sudo tee -a /etc/pacman.conf >/dev/null

しかし、上記のように、これはPOSIXで指定された動作ではありません。-eシェルは、代わりにリテラルの後にリテラルの束を含む文字列をエコーするだけの場合があります\n。それを行うPOSIXの方法は、 ;printfの代わりに使用することです。echo引数は自動的に処理されますが、末尾に改行が自動的に追加されないため、そこにもecho -e余分な行を追加する必要があります。\n

printf '[archlinuxfr]\nServer = http://repo.archlinux.fr/$arch\n \n' | 
  sudo tee -a /etc/pacman.conf >/dev/null

これらのソリューションのいずれかを使用すると、コマンドが引数文字列として取得するものには2文字のシーケンスが含まれ、それを改行に変換する\nのはコマンドプログラム自体(printfまたは内のコード)次第です。echo最近の多くのシェルでは、ANSI引用符$'...を使用するオプションがあります。これにより、コマンドプログラムが文字列を認識する前に、'シーケンス\nリテラルの改行に変換します。つまり、このような文字列は、プレーン-eオールドレスを含むすべてのコマンドで機能しechoます。

echo $'[archlinuxfr]\nServer = http://repo.archlinux.fr/$arch\n ' | 
  sudo tee -a /etc/pacman.conf >/dev/null

ただし、ANSI引用符は、より移植性がecho -eありますが、それでも非POSIX拡張機能です。

繰り返しになりますが、これらはすべてオプションですが、私はtee <<EOF上記のストレートソリューションを好みます。

于 2012-04-13T16:57:22.277 に答える
58

問題は、リダイレクトがによってではなく、元のシェルによって処理されていることsudoです。>>シェルは心を読むことができず、その特定のものがそれのためではなく、のためのものであることを知りませんsudo

必要がある:

  1. リダイレクトを引用します(したがって、リダイレクトはに渡されますsudo)
  2. および使用しますsudo -s(つまりsudo、シェルを使用して引用符で囲まれたリダイレクトを処理します)。
于 2012-04-13T03:40:18.867 に答える
18

http://www.innovations.com/blog/?p=2758

上記の手順はそれほど明確ではないため、そのブログ投稿の手順を使用しています。例があるので、何をする必要があるかを簡単に確認できます。

$ sudo 猫 /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 bash
$ sudo ls /root/example.gz
/root/example.gz

于 2012-06-13T13:57:00.857 に答える
1

STEP 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

STEP 3実行機能

$ write_pacman
于 2014-04-03T17:16:42.490 に答える