mirror of
https://github.com/LCTT/TranslateProject.git
synced 2024-12-29 21:41:00 +08:00
381 lines
11 KiB
Markdown
381 lines
11 KiB
Markdown
|
[#]: collector: (lujun9972)
|
|||
|
[#]: translator: ( )
|
|||
|
[#]: reviewer: ( )
|
|||
|
[#]: publisher: ( )
|
|||
|
[#]: url: ( )
|
|||
|
[#]: subject: (Use this script to create, save, and run different rsync configurations via named profiles)
|
|||
|
[#]: via: (https://opensource.com/article/20/1/create-save-run-rsync-configurations)
|
|||
|
[#]: author: (Petr Beránek https://opensource.com/users/pberanek)
|
|||
|
|
|||
|
Use this script to create, save, and run different rsync configurations via named profiles
|
|||
|
======
|
|||
|
A quick explanation of the rpf script.
|
|||
|
![Person drinking a hat drink at the computer][1]
|
|||
|
|
|||
|
The **rpf** script allows you to create, save, and run different rsync configurations via named profiles.
|
|||
|
|
|||
|
For example, create a new profile named **backup** by typing **rpf -c backup**. Assume that the username is **user**.
|
|||
|
|
|||
|
**rpf** creates the following directories:
|
|||
|
|
|||
|
* **/home/user/.rpf**
|
|||
|
* **/home/user/.rpf/shared** where you can place config files shared by multiple profiles
|
|||
|
* **/home/user/.rpf/profiles** where all profiles are saved as subdirectories
|
|||
|
|
|||
|
|
|||
|
|
|||
|
**rpf** also created **/home/user/.rpf/profiles/backup** that contains the files **conf** and **excluded**.
|
|||
|
|
|||
|
The **conf** file defines rsync's configuration:
|
|||
|
|
|||
|
|
|||
|
```
|
|||
|
# rsync config template
|
|||
|
#
|
|||
|
# Write each rsync option on separate line. For option details see man rsync.
|
|||
|
# Empty lines and lines starting with # are ignored. Dynamic references
|
|||
|
# (e.g. using command substitution) are not supported.
|
|||
|
#
|
|||
|
# Config files shared between different profiles should be saved in
|
|||
|
# /home/user/.rpf/shared
|
|||
|
#
|
|||
|
# Example configuration:
|
|||
|
#
|
|||
|
\--verbose
|
|||
|
\--archive
|
|||
|
\--human-readable
|
|||
|
# exclude all files that match pattern in:
|
|||
|
\--exclude-from=/home/user/.rpf/profiles/backup/exclude
|
|||
|
\--relative
|
|||
|
# perform trial run, make no changes
|
|||
|
\--dry-run
|
|||
|
# source, e.g.
|
|||
|
/home/user
|
|||
|
# destination, e.g.
|
|||
|
/mnt/usb_drive/users_backup
|
|||
|
```
|
|||
|
|
|||
|
Now you can edit, add, or remove rsync options as needed.
|
|||
|
|
|||
|
In **exclude**, you can define paths or patterns of files and directories you want to exclude from the transfer. To exclude **Trash** and **Downloads**, add the following lines:
|
|||
|
|
|||
|
|
|||
|
```
|
|||
|
\- /home/user/.local/share/Trash
|
|||
|
\- /home/user/Downloads
|
|||
|
```
|
|||
|
|
|||
|
Or to transfer only **Documents** and **Projects** and exclude everything else:
|
|||
|
|
|||
|
|
|||
|
```
|
|||
|
\+ /home/user/Documents
|
|||
|
\+ /home/user/Projects
|
|||
|
\- **
|
|||
|
```
|
|||
|
|
|||
|
For subtler pattern configurations, see the FILTER RULES section of **man rsync**, or Google for tutorials.
|
|||
|
|
|||
|
When you are ready, you can start rsync transfer by typing **rpf backup**.
|
|||
|
|
|||
|
That's it.
|
|||
|
|
|||
|
For additional **rpf** options, see **rpf --help**.
|
|||
|
|
|||
|
### Security
|
|||
|
|
|||
|
Please be aware that **rpf** is not secure against code injection in the **conf** file. Any additional code (e.g., **; ./run_evil_script**) will also be executed. Therefore, protect your **.rpf/** config directory from malicious users by implementing appropriate permissions. Moreover, exploiting this behavior can lead to unexpected side effects.
|
|||
|
|
|||
|
### The script
|
|||
|
|
|||
|
|
|||
|
```
|
|||
|
#!/usr/bin/env bash
|
|||
|
#
|
|||
|
# Simple rsync profiler
|
|||
|
#
|
|||
|
# Author: [petrberanek.mail@gmail.com][2] (Petr Beranek)
|
|||
|
#
|
|||
|
# For usage details type `rpf --help'
|
|||
|
#
|
|||
|
|
|||
|
set -o errexit
|
|||
|
set -o nounset
|
|||
|
|
|||
|
__name=$(basename "${0}")
|
|||
|
__version="0.1"
|
|||
|
|
|||
|
config_dir="${HOME}/.rpf"
|
|||
|
profiles_dir="${config_dir}/profiles"
|
|||
|
shared_dir="${config_dir}/shared"
|
|||
|
help="\
|
|||
|
Usage: ${__name} [OPTION...] PROFILE_NAME
|
|||
|
|
|||
|
${__name} is simple rsync profiler that stores your different rsync
|
|||
|
configurations in named profiles.
|
|||
|
|
|||
|
Options:
|
|||
|
-c, --create-profile PROFILE_NAME create new profile (profile data
|
|||
|
are stored in ${config_dir}/PROFILE_NAME).
|
|||
|
Profile name can contain alphanumeric
|
|||
|
characters only.
|
|||
|
-s, --show-profile-config PROFILE_NAME show content of profile
|
|||
|
configuration file (stored in
|
|||
|
${config_dir}/PROFILE_NAME)
|
|||
|
-l, --list-profiles list all available profiles
|
|||
|
-h, --help show this help
|
|||
|
|
|||
|
Example:
|
|||
|
Create new profile by typing
|
|||
|
${__name} -c PROFILE_NAME
|
|||
|
|
|||
|
edit its config files stored by default in
|
|||
|
${profiles_dir}/PROFILE_NAME
|
|||
|
|
|||
|
and then run it by typing
|
|||
|
${__name} PROFILE_NAME
|
|||
|
|
|||
|
That's it.
|
|||
|
|
|||
|
${__name} comes with ABSOLUTELY NO WARRANTY. This is free software,
|
|||
|
and you are welcome to redistribute it under certain conditions. See
|
|||
|
the GNU General Public Licence for details.
|
|||
|
|
|||
|
Email bug reports or enhancement requests to [petrberanek.mail@gmail.com][2].
|
|||
|
"
|
|||
|
|
|||
|
create_profile() {
|
|||
|
# Create dir with given profile name and with default content.
|
|||
|
#
|
|||
|
# Arguments: $1 -- profile name
|
|||
|
#
|
|||
|
# Creates files: conf, exclude
|
|||
|
#
|
|||
|
# If dir with the same name already exists, exits with error.
|
|||
|
#
|
|||
|
|
|||
|
local profile_name="${1}"
|
|||
|
local profile_dir="${profiles_dir}/${profile_name}"
|
|||
|
|
|||
|
# create default rpf dirs if missing
|
|||
|
if [[ ! -d "${profiles_dir}" ]]; then
|
|||
|
echo "Creating ${profiles_dir}"
|
|||
|
mkdir --parents "${profiles_dir}"
|
|||
|
fi
|
|||
|
if [[ ! -d "${shared_dir}" ]]; then
|
|||
|
echo "Creating ${shared_dir}"
|
|||
|
mkdir --parents "${shared_dir}"
|
|||
|
fi
|
|||
|
|
|||
|
# don't overwrite existing profile
|
|||
|
if [[ -d "${profile_dir}" ]]; then
|
|||
|
echo "${__name}: error: profile already exists."
|
|||
|
exit 1
|
|||
|
fi
|
|||
|
|
|||
|
echo "Creating ${profile_dir}"
|
|||
|
mkdir "${profile_dir}"
|
|||
|
|
|||
|
# create `conf' template
|
|||
|
local conf="${profile_dir}/conf"
|
|||
|
echo "Creating ${conf}"
|
|||
|
cat << EOF > "${conf}"
|
|||
|
# rsync config template
|
|||
|
#
|
|||
|
# Write each rsync option on separate line. For details see man rsync.
|
|||
|
# Empty lines and lines starting with # are ignored. Dynamic references
|
|||
|
# (e.g. using command substitution) are not supported.
|
|||
|
#
|
|||
|
# Config files shared between different profiles should be saved in
|
|||
|
# ${shared_dir}
|
|||
|
#
|
|||
|
# Example configuration:
|
|||
|
#
|
|||
|
\--verbose
|
|||
|
\--archive
|
|||
|
\--human-readable
|
|||
|
# file with patterns of files and directories in source excluded
|
|||
|
# from transfer
|
|||
|
\--exclude-from="${profiles_dir}/${profile_name}/exclude"
|
|||
|
\--relative
|
|||
|
# perform trial run, make no changes
|
|||
|
\--dry-run
|
|||
|
# source, e.g.
|
|||
|
${HOME}
|
|||
|
# destination, e.g.
|
|||
|
/mnt/usb_drive/my_backup
|
|||
|
EOF
|
|||
|
|
|||
|
# create `exclude' template
|
|||
|
local exclude="${profile_dir}/exclude"
|
|||
|
echo "Creating ${exclude}"
|
|||
|
cat << EOF > "${exclude}"
|
|||
|
# \\`exclude' template
|
|||
|
#
|
|||
|
# Lines starting with # or ; are ignored. For details see man rsync,
|
|||
|
# section FILTER RULES.
|
|||
|
#
|
|||
|
EOF
|
|||
|
|
|||
|
# all done
|
|||
|
echo "OK"
|
|||
|
echo "Edit profile config files in ${profile_dir} to fit your needs."
|
|||
|
}
|
|||
|
|
|||
|
list_profiles() {
|
|||
|
# Show all available rpf profiles.
|
|||
|
#
|
|||
|
# Assumes that all dirs in $profiles_dir are profiles.
|
|||
|
#
|
|||
|
|
|||
|
for item in "${profiles_dir}"/*; do
|
|||
|
if [[ -d "${item}" ]]; then
|
|||
|
basename "${item}"
|
|||
|
fi
|
|||
|
done
|
|||
|
}
|
|||
|
|
|||
|
show_help() { echo "${help}"; }
|
|||
|
|
|||
|
show_profile_config() {
|
|||
|
# Show configuration file for given profile.
|
|||
|
#
|
|||
|
# Arguments: $1 -- profile name
|
|||
|
#
|
|||
|
|
|||
|
local profile_name="${1}"
|
|||
|
less "${profiles_dir}/${profile_name}/conf"
|
|||
|
}
|
|||
|
|
|||
|
check_profile_name() {
|
|||
|
# Check that name is not empty and contains alphanumeric chars only.
|
|||
|
#
|
|||
|
# Arguments: $1 -- profile name
|
|||
|
#
|
|||
|
# If test fails, exits with error.
|
|||
|
#
|
|||
|
|
|||
|
if [[ -z "${1}" ]]; then
|
|||
|
echo "${__name}: error: empty profile name."
|
|||
|
exit 1
|
|||
|
elif [[ "${1}" =~ [^a-zA-Z0-9] ]]; then
|
|||
|
echo "${__name}: error: non-alphanumeric characters in profile name."
|
|||
|
exit 1
|
|||
|
fi
|
|||
|
}
|
|||
|
|
|||
|
check_profile_exists() {
|
|||
|
# Check that $profile_name exists and is a directory.
|
|||
|
#
|
|||
|
# Arguments: $1 -- profile name
|
|||
|
#
|
|||
|
# If test fails, exits with error.
|
|||
|
#
|
|||
|
|
|||
|
local profile_name="${1}"
|
|||
|
if [[ ! -d "${profiles_dir}/${profile_name}" ]]; then
|
|||
|
echo "${__name}: error: profile ${profile_name} does not exist."
|
|||
|
exit 1
|
|||
|
fi
|
|||
|
}
|
|||
|
|
|||
|
check_num_args() {
|
|||
|
# Check that value of $1 = number of arguments (excluding $1)
|
|||
|
#
|
|||
|
# Arguments: $1 -- limit (positive int)
|
|||
|
#
|
|||
|
# If test fails, exits with error.
|
|||
|
#
|
|||
|
|
|||
|
local num_args=$(( ${#} - 1 )) # do not count $1 in total num of args
|
|||
|
if [[ "${1}" -ne "${num_args}" ]]; then
|
|||
|
echo "${__name}: error: expected num args: ${1}, received: $num_args"
|
|||
|
exit 1
|
|||
|
fi
|
|||
|
}
|
|||
|
|
|||
|
run_rsync() {
|
|||
|
# Run rsync with configuration coresponding to given profile name.
|
|||
|
#
|
|||
|
# Arguments: $1 -- profile name
|
|||
|
#
|
|||
|
|
|||
|
local profile_name="${1}"
|
|||
|
local visual_div="=============================="
|
|||
|
local parsed_args
|
|||
|
parsed_args=$(grep --invert-match '^#' "${profiles_dir}/${profile_name}/conf" \
|
|||
|
| tr '\n' ' ')
|
|||
|
|
|||
|
# Print debug info
|
|||
|
echo "${visual_div}"
|
|||
|
echo "${__name} version: ${__version}"
|
|||
|
echo "args: ${parsed_args}"
|
|||
|
echo "${visual_div}"
|
|||
|
|
|||
|
# Expand $parsed_args - each item from conf file becomes rsync argument
|
|||
|
# shellcheck disable=SC2086
|
|||
|
rsync ${parsed_args}
|
|||
|
}
|
|||
|
|
|||
|
if [[ "${#}" == 0 ]]; then
|
|||
|
show_help
|
|||
|
exit 1
|
|||
|
fi
|
|||
|
while [[ "${#}" -gt 0 ]]; do
|
|||
|
case "${1}" in
|
|||
|
-c | --create-profile)
|
|||
|
check_num_args 2 "${@}"
|
|||
|
shift
|
|||
|
check_profile_name "${1:-}" # If $1 is not declared, set it empty.
|
|||
|
create_profile "${1}"
|
|||
|
exit 0;;
|
|||
|
-s | --show-profile-config)
|
|||
|
check_num_args 2 "${@}"
|
|||
|
shift
|
|||
|
check_profile_name "${1:-}"
|
|||
|
check_profile_exists "${1}"
|
|||
|
show_profile_config "${1}"
|
|||
|
exit 0;;
|
|||
|
-l | --list-profiles)
|
|||
|
check_num_args 1 "${@}"
|
|||
|
list_profiles
|
|||
|
exit 0;;
|
|||
|
-h | --help)
|
|||
|
check_num_args 1 "${@}"
|
|||
|
show_help
|
|||
|
exit 0;;
|
|||
|
-*)
|
|||
|
echo "${__name}: error: unknown option \\`${1}'"
|
|||
|
exit 1;;
|
|||
|
*)
|
|||
|
check_num_args 1 "${@}"
|
|||
|
check_profile_name "${1:-}"
|
|||
|
check_profile_exists "${1}"
|
|||
|
run_rsync "${1}"
|
|||
|
exit 0;;
|
|||
|
esac
|
|||
|
shift
|
|||
|
done
|
|||
|
```
|
|||
|
|
|||
|
* * *
|
|||
|
|
|||
|
This was originally published in [Petr Beranek's GitHub repository][3] and it is licensed under GPLv3.
|
|||
|
|
|||
|
--------------------------------------------------------------------------------
|
|||
|
|
|||
|
via: https://opensource.com/article/20/1/create-save-run-rsync-configurations
|
|||
|
|
|||
|
作者:[Petr Beránek][a]
|
|||
|
选题:[lujun9972][b]
|
|||
|
译者:[译者ID](https://github.com/译者ID)
|
|||
|
校对:[校对者ID](https://github.com/校对者ID)
|
|||
|
|
|||
|
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
|||
|
|
|||
|
[a]: https://opensource.com/users/pberanek
|
|||
|
[b]: https://github.com/lujun9972
|
|||
|
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/coffee_tea_laptop_computer_work_desk.png?itok=D5yMx_Dr (Person drinking a hat drink at the computer)
|
|||
|
[2]: mailto:petrberanek.mail@gmail.com
|
|||
|
[3]: https://github.com/beranep/rpf
|