Bash

在創建腳本以更新 /etc/hosts 文件中的主機名時遇到多個問題?

  • October 17, 2017

我對腳本完全陌生,因此需要幫助來解決這個問題。

我們有大約 3000 台虛擬機和 450 台物理伺服器,它們是基於 Linux 的伺服器(從 9.x 開始,很少有 ubuntu,從 8.X 開始很少有 Susu,從 4.x 到 7.4 大部分是 RHEL)所有這些我都需要在它們各自的 /etc/hosts 文件中添加一些帶有 IP 詳細資訊的主機名條目。

我在每台伺服器上都有不同的使用者,我可以使用完全 sudoers 訪問權限因此我創建了一個包含主機名、使用者名和密碼格式的 CSV 文件。其中包含登錄所需的詳細資訊。文件名是“hostname_logins.csv”

我需要上傳一個文件(即 hostname_list 到這些伺服器中的每一個,然後在每個伺服器主機文件中更新這些相同的詳細資訊。

我將使用一台 RHEL 6 伺服器執行此腳本。(所有其他主機都可以從此伺服器解析並且可以訪問,我已經確認過了。)

因此需要幫助來修復這個腳本。

腳本不確定其中有什麼問題,因為我是腳本新手:

#!/bin/bash

while read hostname_login user_name user_password
do
       scp -p ./hostname_list $user_name:$user_password@$hostname_login:/tmp
       ssh -eS $user_name:$user_password@$hostname_login [bash -c "echo rishee | sudo -S mv /tmp/hostname_list ./hostname_list && cp -p /etc/hosts /etc/hosts.bkp && cat ./hostname_list >> /etc/hosts && rm -f ./hostname_list"]
done < hostname_logins.csv

我需要把它作為一個單一的腳本,它可以在所有這些伺服器上工作。提前致謝。

我沒有嘗試在 shell 中讀取 CSV,所以這將是一個不完整的回复。我通常使用 Perl 或 AWK 來做這些事情。

第一個問題是 shell 使用空白來分隔行中的欄位,因此您必須將欄位拆分為“,”(逗號)。所以

IFS=","
while read hostname_login....

但是,如果它是“真實的”CSV,那麼它可能看起來像這樣

"hostname_login",username,"userpass"

即關於它是否有引號的可變性。如果不是這種情況,您就可以自由回家了。

我不熟悉

$$ bash -c $$你的 ssh 中的語法,所以我不能評論它。我傾向於使用單引號 (’) 代替。 我認為您可以跳過將 /tmp/hostname_list 移動到主目錄的步驟。你可以做

ssh -eS $user_name:$user_password@$hostname_login [echo rishee | sudo -S cp -p /etc/hosts /etc/hosts.bkp && cat /tmp/hostname_list >> /etc/hosts && rm -f /tmp/hostname_list"]

一旦確定是否如此,我將更新我的答案

$$ $$事物是真實的事物。我只在模式匹配上下文中使用過它,並作為條件測試的別名。(即for filename in hostname[0-9]; do ...if [ -n "$var" ]; then...) ssh+sudo 也將面臨挑戰,其中 ssh 無法分配 pty 並且 sudo 對此進行了調整。我不得不四處尋找,但我覺得我們通過調整 /etc/sudo.config 或其他東西來解決這個問題,這不是最佳的。

同樣,正如所寫,您只需為初始 mv /tmp/hostname ./hostname 執行 sudo。

就個人而言,由於您的文件內容是靜態的,我會通過預先編寫您想要在另一端執行的內容並複制它來簡化整個轉義序列的內容:

cat > hostname_list_script.sh

#/bin/bash

if ! cp -p /etc/hosts /etc/hosts.bkp; then 
 echo "Failed to backup /etc/hosts"
 exit 1 
fi

cat <<EOM  >> /etc/hosts
^D
cat hostname_list >> hostname_list_script.sh
EOM
^D

您正在複製的文件現在在頂部有一點文本,您希望附加的內容,然後在底部有一些文本,即

[...]
fi

cat <<EOM >> /etc/hosts
10.90.70.5  hostname1
10.90.70.4  hostname2
10.90.70.6  hostname3
EOM

然後你的主腳本可以閱讀

#/bin/bash

IFS=","

while read hostname_login user_name user_password
do 
  scp -p ./hostname_list_script.sh $user_name:$user_password@$hostname_login:/tmp 
  echo sudo_password | ssh -t -eS $user_name:$user_password@$hostname_login '/usr/bin/sudo -S -s bash /tmp/hostname_list_script.sh'
done < hostname_logins.csv

實際上,我看到了另一個問題。我認為您需要根據登錄名更改傳遞給 sudo 的密碼:

echo $user_password | ssh ....

我認為當每台機器的登錄密碼不同時,sudo 是否會在所有機器上採用靜態密碼是值得懷疑的。

CAVEAT EMPTOR:我沒有測試上面提到的 pty 可用性問題,以及你是否不需要引用bash scriptsudo 的參數。在我看來,這是可行的,但您可能需要擺弄引用才能使其正確。我不需要更新我的 /etc/hosts 文件,所以我沒有測試它。

正如 Spiderice 所提到的,在您的一台機器上安裝 BIND(DNS 名稱伺服器)可能更容易,只需執行一個腳本,將該機器的 IP 地址添加到 /etc/resolv.conf 而不是附加到 /etc/hosts。當我第一次開始閱讀您的問題時,我想知道我們是否還必須參與刪除主機和重複刪除您的 /etc/hosts 條目。我想知道這是否可能是幾個月後您今天添加的一些主機消失或重命名時的下一個問題。

我在解決如何使這樣的事情發揮作用方面的建議將逐步建立。所以首先調試while循環:

#!/bin/bash
while read hostname_login user_name user_password
do 
   echo "$hostname_login / $user_name / $user_password"
done  < hostname_logins.csv

然後從 hostname_logins.csv 文件中獲取前 4 行並改進 while 循環的內容,首先在 while 循環中添加文件複製。接下來從命令行工作到一個主機的 ssh 執行行。一旦你完成了所有工作,你就可以將你的進化行粘貼到腳本的 while 循環中。在您的 4 主機測試集上再次進行測試,一旦您確定一切都已解決,然後將您的完整主機列表提供給它。

引用自:https://serverfault.com/questions/878941