Shell

read 命令在 Makefile 中不起作用

  • November 11, 2016

我有一個 make 腳本來執行 3 個任務:

  1. 導入 MySQL 數據庫
  2. 移動配置文件
  3. 配置配置文件

對於這些任務,腳本需要 3 個輸入:

  1. MySQL主機
  2. MySQL 使用者名
  3. MySQL 密碼

出於某種原因,每當我read輸入時,它都會保存到正確的變數中,但內容是我保存的變數名,沒有第一個字母。我似乎無法找出它為什麼這樣做。

這是Makefile

SHELL := /bin/bash

default:
       @echo "Welcome!";\
       echo -n "Please enter the MySQL host (default: localhost):";\
       read host;\
       host=${host:-localhost};\
       echo -n "Please enter the MySQL username:";\
       read username;\
       echo -n "Please enter the MySQL password:";\
       read -s password;\
       mv includes/config.php.example includes/config.php 2>/dev/null;true;\
       sed 's/"USER", ""/"USER", "$(username)"/g' includes/config.php > includes/config.php;\
       sed 's/"PASSWORD", ""/"PASSWORD", "$(password)"/g' includes/config.php > includes/conf$
       echo $username;\
       echo $password;\
       mysql -u "$username" -p"$password" codeday-team < ./codeday-team.sql;\
       echo "Configuration complete. For further configuration options, check the config file$
       exit 0;

輸出是:

Welcome!
Please enter the MySQL host (default: localhost):
Please enter the MySQL username:<snip>    
Please enter the MySQL password:sername
assword
ERROR 1045 (28000): Access denied for user 'sername'@'localhost' (using password: YES)
Configuration complete. For further configuration options, check the config file includes/config.php

如您所見,它輸出sernameassword。對於我的生活,我無法解決這個問題!

雖然這篇文章的目的是解決read錯誤,但我會很感激任何建議、錯誤報告或建議。我可以獎勵他們。

謝謝你的幫忙!

make在那裡混合shell和變數。兩者make和 shell 都$用於它們的變數。

在 Makefile 中,變數是$(var)or$v用於單字母變數,$var或者${var}在 shell 中。

但是如果你寫$var在一個 Makefile 中,make就會把它理解為$(v)ar. 如果您想將文字傳遞$給 shell,您需要將其輸入為$$,如 in $$varor$${var}這樣它就成為shell 的$varor ${var}

此外,make執行sh,而不是bash解釋該程式碼(編輯,抱歉錯過了您的上述程式碼,請注意,許多系統根本SHELL := /bin/bash沒有bash,並且是 GNU 特定的),因此您需要在那裡使用語法。,是/語法,不是語法。/bin``bash``:=``sh``echo -n``read -s``zsh``bash``sh

最好在這裡添加一個zsh/bash腳本來做到這一點(並添加一個建構依賴項bash)。就像是:

#! /usr/bin/env bash
printf 'Welcome\nPlease enter the MySQL host (default: localhost): '
read host || exit
host=${host:-localhost}
printf "Please enter the MySQL username: "
read username || exit
printf "Please enter the MySQL password:"
IFS= read -rs password || exit
printf '\n'
mv includes/config.php.example includes/config.php 2>/dev/null
repl=${password//\\/\\\\}
repl=${repl//&/\\&}
repl=${repl//:/\\:}
{ rm includes/config.php && 
 sed 's/"USER", ""/"USER", "'"$username"'"/g
      s:"PASSWORD", "":"PASSWORD", "'"$repl"'"/g' > includes/config.php
} < includes/config.php || exit
mysql -u "$username" -p"$password" codeday-team < ./codeday-team.sql || exit

echo "Configuration complete. For further configuration options, check the config file"

它解決了更多問題:

  • -r如果要允許使用者在密碼中使用反斜杠,則在讀取密碼時需要。
  • 如果IFS=您想允許使用者擁有以空格開頭或結尾的密碼,則需要
  • 同樣適用於使用者名,但在這裡我們假設使用者不會對使用者名使用任何愚蠢的東西,並且可以將空白剝離和反斜杠處理視為 /feature/。
  • 你的;true後繼mv沒有做你認為它做的事。它不會取消errexit選項的效果(對於make使用 呼叫 shell 的實現-e)。你需要||true。在這裡,我們沒有使用,errexit而是|| exit在需要的地方自行處理錯誤。
  • 您需要轉義反斜杠&s:pattern:repl:分隔符(此處:),否則它將不起作用(並且可能會產生令人討厭的副作用)。
  • 你不能這樣做sed ... < file > file,因為在開始file之前會被截斷sed。一些sed實現支持一個-ior-i ''選項。或者,您可以使用perl -pi. 在這裡,我們正在做相當於perl -pi手動操作(在打開以供讀取後刪除並重新創建輸入文件),但不處理文件的元數據。

在這裡,最好使用範例一作為輸入,最後一個作為輸出。

它仍然沒有解決更多問題:

  • newconfig.php是使用從 current 派生的權限創建的,umask這可能是世界可讀的並由執行的使用者擁有make。如果目錄不受其他限制,您可能需要調整umask和/或更改所有權,includes因為該文件包含敏感資訊。
  • 如果密碼包含"字元,則可能會中斷(這次是php)。php您可能希望禁止這些(通過返回錯誤)或以該文件的正確語法為它們添加另一層轉義。您可能會遇到與反斜杠類似的問題,並且您可能還想排除非 ascii 或控製字元。
  • 在命令行上傳遞密碼mysql通常是個壞主意,因為這意味著它會顯示在ps -f. 最好使用:
mysql --defaults-file=<(
  printf '[client]\nuser=%s\npassword="%s"\n' "$username" "$password") ...

printf是內置的,它不會出現在ps輸出中。

  • $host未使用該變數。
  • 像這樣提示使用者意味著您的腳本不能輕易自動化。您可以從參數中獲取輸入,或者(對於密碼更好)使用環境變數。

引用自:https://unix.stackexchange.com/questions/322517