.dotファイル(.dotディレクトリではない)をディレクトリにコピーしたいと思います。これを行うには、オペレーティングシステム(MacOS)でユーザーパスワードを入力する必要があります。私はこれを行う関数を作成し、それを次のような大きなバックアップスクリプトに統合したいと思います。
#!/bin/zsh
source ~/.zshrc
set -o errexit
set -o nounset
set -o pipefail
copy_dotfiles()
{
MAIN_PATH="/Users/user01/"
DOTFILE_DIR="${MAIN_PATH}Documents/dot_files"
echo $DOTFILE_DIR
mkdir $DOTFILE_DIR
for f in $MAIN_PATH.[!.]*; do
if [[ -f $f ]]; then
echo "$f" is a file
DOTFILE=`echo $f | sed 's/\/Users\/user01\///g'`
echo "$DOTFILE" is a file
cp $f ${DOTFILE_DIR}/${DOTFILE} || exit 1
elif [[ -d $f ]]; then
echo "$f" is a dir
continue
else
echo "$f is not valid"
exit 1
fi
done
}
sudo copy_dotfiles || exit 1
ただし、スクリプトを実行すると、次の結果が表示されます。
sudo: copy_dotfiles: command not found
答え1
sudo
シェル関数ではありません。実行可能ファイルを実行する別の実行可能ファイルです。 :)
したがって、シェル機能を実行できません。それでもシェルスクリプトを実行できます!したがって、動作させるには、sudo
このスクリプトからこれを省略し、sudoを介してスクリプト全体を実行します。
あなた本当にsource ~/.zshrc
とにかく削除する必要がありますが、特にスクリプトをrootとして実行するとき。
答え2
このコードのインライン注釈:
#!/bin/zsh source ~/.zshrc
呼び出すユーザーの対話型シェルカスタムファイルをスクリプトにインポートしたいのはなぜですか?これは言葉ではありません。
set -o errexit
設定しましたが、キャンセルされた状態でエフェクトをerrexit
使用しようとしました。somefunction || ...
errexit
set -o nounset set -o pipefail
set -o errexit -o nounset -o pipefail
POSIXシェルでこれを行うことはできません。setopt errexit nounset pipefail
copy_dotfiles() { MAIN_PATH="/Users/user01/" DOTFILE_DIR="${MAIN_PATH}Documents/dot_files"
名前がすべて大文字の変数は、通常、環境変数またはglobスコープの変数に使用されます。関数でグローバル変数を固定値に設定するのは奇妙です。
copy_dotfiles() { # Arg: username
local target_dir=~$1/Documents/dot_files
ユーザー名をパラメータとして使用 copy_dotfiles
し、ホームディレクトリにターゲットディレクトリのローカル変数を設定する方が合理的です。
パラメータを対象としない関数を定義することは意味がありません。
echo $DOTFILE_DIR
印刷する前に、パラメータを慎重にecho
変換してください。使用するのが最善です:print -r -- $DOTFILE_DIR
またはprintf '%s\n' $DOTFILE_DIR
mkdir $DOTFILE_DIR
これを実行すると、ターゲットユーザーの代わりにそのユーザーを使用して新しいディレクトリが作成されますroot
。root
関数の終了状態を確認せずに関数のmkdir
終了errexit
状態を処理すると、その関数がキャンセルされ、残りのコードが失敗するmkdir
可能性があります。たとえば、ユーザーが機密システムへのシンボリックリンクを作成した~/Documents/dot_files
場合、または機密ファイルへのシンボリックリンクを含むファイルを含むディレクトリを作成した場合、重大な結果が生じる可能性があります/etc/shadow
。/root/.bashrc
また、で終わる場合にはcmd $anything_dynamic
原則cmd -- $anything_dynamic
として。$anything_dynamic
-
for f in $MAIN_PATH.[!.]*; do
$dir/file-within
変数の値に末尾の文字列を追加してdoを実行する代わりに、pathname / dir変数をディレクトリパスとして定義してそれを使用する方が一般的です。/
${dir}file-within
.
また、zsh globにはnorは含まれていません..
。 zshでは、ファイルを除外して除外しても、否定設定^
よりも優先されます。!
.[!.]*
.
..
..file
N
空のリストを受け入れ、ローカル変数を宣言するためにglob修飾子を使用することもできますf
。
local f
for f in $source_dir/.*(N); do
if [[ -f $f ]]; then echo "$f" is a file
もっと好きですprint -r -- $f is a regular file or symlink to regular file
。
また、zsh
globはタイプ別にファイルを選択できるため、ここで繰り返す必要はありません[[...]]
。
DOTFILE=`echo $f | sed 's/\/Users\/user01\///g'` echo "$DOTFILE" is a file cp $f ${DOTFILE_DIR}/${DOTFILE} || exit 1
行ベースでファイルパスを複数行で構成できるため、他のテキストユーティリティを使用してファイルパスを変更するのは通常間違いsed
です。テキスト置換演算子(kshとcshを含む)が組み込まれており、パスの尾を取得しますが、ここでは両方を実行するため、置き換えを実行する必要はありません。sed
zsh
${var/pattern/replacement}
$var:s/string/replacement/
$var:t
cp
にコピーそしてにコピー。
cp -- $f $target_dir/
$f
そのパスが保存されているディレクトリにコピーされます$target_dir
。
ただし、rootとして実行すると危険です。
elif [[ -d $f ]]; then echo "$f" is a dir continue else echo "$f is not valid" exit 1 fi done } sudo copy_dotfiles || exit 1
sudo
実行するコマンドファイルの名前またはパスを使用する外部コマンドです。シェルや他のプログラミング言語では関数名を取得できません。
シェルを実行するように指示することができ、シェルは以下を使用できる関数を定義して呼び出します。
exec sudo zsh -o errexit -o nounset -o pipefail -c '
'"$(typeset -f -- copy_dotfile)"'
"$0" "$@"' copy_dotfile "$@"
しかし、ここではスクリプト全体がまさにその関数なので、rootとして呼び出すこともできますし、スクリプトがスーパーユーザーでない場合はrootとして再実行してみることもできます。
#! /bin/zsh -
set -o nounset
# reexecute as root if effecive uid is not 0 (not privileged).
(( EUID == 0 )) || exec sudo -u root -- "$0" "$@"
user=${1?}
ERRNO=0 USERNAME=$user # drop privileges by switching all uids and gids
# to those of the target user
(( ERRNO )) && exit 1 # abort if we couldn't drop privileges
# cd to the source directory
cd -P -- ~$user || exit
# hidden regular (.) files.
dotfiles=( .*(N.) )
destdir=Documents/dot_files
mkdir -p -- $destdir || exit
if (( $#dotfiles )) exec cp -pP -- $dotfiles $destdir/
(テストされていません)