
プロジェクトを生成するための次のスクリプトがあります。
clear
version="0.0.2"
echo "Project creator"
echo "---------------"
# ask user to specify a directory (could start with spelled-out home directory)
directoryName=""
# Input must meet the following criteria:
# 1.) No spaces at all in the directory path
# 2.) some characters must be entered
while [[ ${#directoryName} -eq 0 || $directoryName == *" "* ]]
do
echo -e "\nEnter the full directory of the project (no spaces):"
read directoryName
done
echo "You entered: $directoryName"
# uate directoryName so that the rest of the code can understand it
# create directory if it does not exist
eval mkdir "$directoryName"
# if successful
if [ $? -eq 0 ]
then
# call executable in /home/miwarren/CPPFileCreator to create a main.cpp file to put in the folder
$HOME/CPPFileCreator/a.out $directoryName
# copy a run.sh file into the folder, too...
eval cp $HOME/CPPFileCreator/run.sh $directoryName/run.sh
# you might want to put a fileCreator.sh in the folder as well
eval cp $HOME/fileCreator.sh $directoryName/fileCreator.sh
fi
すべての空白を削除しました(挿入攻撃のために安全でない各文字列に少なくとも1つの空白があるとします)。変数が存在する場合は、ユーザーがパス部分($HOME
ホームディレクトリなど)を綴る必要はありません。
ここで引き続き使用できますかeval
?そうでない場合はどうすればよいですか?
答え1
「変数が存在するときにユーザーがパス部分を綴る必要はありません(たとえば、ホームディレクトリの場合は$ HOME)。」
これは次のことなく実行できますeval
。
$ s='$HOME/.config'
$ s="${s//\$HOME/$HOME}"
$ echo "$s"
/home/john1024/.config
これにはいくつかの制限があります。まず、HOMESとHOMEの両方が置換先の変数名である場合は、誤ったマッチングを防ぐためにHOMESを置き換える必要があります。今後家。
エクスポートしたすべての変数に代替を適用する
バッシュ使用:
while IFS== read -r name val
do
s="${s//\$$name/$val}"
done < <(printenv)
たとえば、
$ export A=alpha; export B=beta
$ s='$HOME/$A/$B'
$ while IFS== read -r name val; do s="${s//\$$name/$val}"; done < <(printenv)
$ echo "$s"
/home/john1024/alpha/beta
このアプローチは変数名を長さで並べ替えないため、上記の変数重複の問題が発生します。
変数名を長さで並べ替えることでこの問題を解決できます。
while IFS== read -r n name val
do
s="${s//\$$name/$val}"
done < <(printenv | awk '/^[^ \t]/{key=$0; sub(/=.*/,"",key); printf "%s=%s\n",length(key),$0}' | sort -rnt=)
ユーザーが変数名を入力した場合いいえ存在しますが、初期文字が短い名前と一致する場合は、短い名前が置き換えられます。これが重要な場合は、次のコードを使用して、この変数に中括弧表記を使用するようにユーザーに要求することで、これを回避できます。
while IFS== read -r n name val
do
s="${s//\$\{$name\}/$val}"
done < <(printenv | awk '/^[^ \t]/{key=$0; sub(/=.*/,"",key); printf "%s=%s\n",length(key),$0}' | sort -rnt=)
たとえば、
$ s='${HOME}/${A}/${B}'
$ while IFS== read -r n name val; do s="${s//\$\{$name\}/$val}"; done < <(printenv | awk '/^[^ \t]/{key=$0; sub(/=.*/,"",key); printf "%s=%s\n",length(key),$0}' | sort -rnt=)
$ echo "$s"
/home/john1024/alpha/beta
答え2
ここで使用することは意味がありませんeval
。スクリプトの修正方法を決定する前に、あなたの要件を慎重に考えて書き留めてください。。あなたの質問を読んでみると、あなたが何をしたいのかについての明確な考えはなく、解決策が期待するものを理解するまで問題を解決できないことは明らかです。
すべての安全でない文字列には少なくとも1つのスペースがあるとします。
いいえ、近いこともありません。スクリプトを使用すると、ユーザーはスペースや改行を含まないすべての文字列を入力できるため、任意のコードを実行できます。ユーザーは代わりにタブとセミコロンを使用できます。スペースがなくても、ユーザーは代替コマンドを入力できます。
`touch /tmp/this_is_executed`somefile
$(touch /tmp/this_is_executed)somefile
これは問題ですか?それはあなたがしたいことに依存します。通常のアカウントでスクリプトを実行しているユーザーが入力しますか?もしそうなら、セキュリティ上の問題はありませんが、スクリプトが標準入力から入力を読み取ることは意味がありません。コマンドライン引数を使用すると、コマンドラインシェルは目的の変数拡張を実行します。スクリプトが高い権限で実行される場合、またはネットワーク経由で入力を受け取る場合、これは絶対に有害であるため、eval
その意味を理解するまで使用しないでください。eval
文字列を引数として受け取り(複数の引数がある場合はスペースで連結)、シェルコードとして実行します。シェルコードを実行したくない場合は、eval
このツールは間違っています。
スクリプトが許可されていない入力を受け取ると、変数拡張を実行するのに間違った場所です。ユーザー権限で実行されるスクリプトに入力を提供するインターフェイスでこれを行います(たとえば、入力がWebブラウザから来る場合はJavascriptを使用します)。スクリプトで指定されたファイル名がユーザーがアクセスできるディレクトリにあることを確認する必要があります。..
ディレクトリツリーのエスケープを許可するシンボリックリンクに注意してください。-
ファイル名の代わりにオプションで解析できる行間。