Bash 脚本“用法”输出格式
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/19507902/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Bash Script "Usage" output formatting
提问by flamusdiu
What is a good way to output help text for a bash script to get the columns lines to be lined up properly?
为 bash 脚本输出帮助文本以使列行正确排列的好方法是什么?
something like:
就像是:
Usage: mycommand [options]
-h| --help this is some help text.
this is more help text.
-1|--first-option this is my first option
-2|--second-option this is my second option
回答by imp25
I like to use cat
for this:
我喜欢用cat
这个:
usage.sh:
用法.sh:
#!/bin/bash
cat <<EOF
Usage: Usage: usage.sh [options]
-h| --help this is some help text.
this is more help text.
-1|--first-option this is my first option
-2|--second-option this is my second option
[options]
-h| --help this is some help text.
this is more help text.
-1|--first-option this is my first option
-2|--second-option this is my second option
EOF
This will output:
这将输出:
cat <<-EOF
usage.sh [options]
-h| --help this is some help text.
this is more help text.
-1|--first-option this is my first option
-2|--second-option this is my second option
EOF
回答by sygibson
Heredocs also have a tab indented option. This allows you to preface each line of code with any number of tabs - and those will be "eaten up" on output, left justifying your output. Note that the trailing 'EOF' (in this example) MUST be fully left indented - the 'EOF' can not be tab indented.
Heredocs 也有一个制表符缩进选项。这允许您在每行代码前添加任意数量的选项卡 - 这些选项卡将在输出中“吃掉”,左对齐输出。请注意,尾随的“EOF”(在本例中)必须完全缩进——“EOF”不能缩进。
Be careful of any editors that are converting tab characters to spaces (eg "vi" option is "expandtab" which converts tabs to spaces). Unfortunately, multiple spaces are not "eaten up" like tabs are. If you use 'expandtab' (or similar options) for code formatting, then the heredoc tab indent method is not likely to be useful to you.
小心任何将制表符转换为空格的编辑器(例如,“vi”选项是将制表符转换为空格的“expandtab”)。不幸的是,多个空格不会像制表符那样被“吃掉”。如果您使用“expandtab”(或类似选项)进行代码格式化,那么heredoc 制表符缩进方法可能对您没有用处。
In the example below, the "<<-" is the syntax for a heredoc to honor the tab indents.
在下面的示例中,“<<-”是heredoc 的语法,以支持制表符缩进。
Example:
例子:
# Put here all the options your script accepts
local options=(
'-c,--config <FILE>'
'-l,--list'
'-r,--run'
'-v,--verbose'
'-n,--dry-run'
'-h,--help'
)
# Put here the corresponding descriptions for every option you specified in the array above
local descriptions=(
"Use the given configuration file instead of the default one"
"List all program related files. if used with \`--verbose\`, the full contents are printed"
"Try to process all the files"
"Turn on verbose output"
"don't store files like alwyas but show only what actions would have been taken if $(basename "##代码##") would have run normally (with or without --run), implies --verbose"
"display help"
)
# Put here the offset options will get
local options_offset=3
# Put here the offset descriptions will get after the longest option
local descriptions_offset_after_longest_option=5
# Put here the maximum length of descriptions spanning
local maximum_descriptions_length=80
# ---------------------------------
# Up until here is the configuration
# ---------------------------------
# First we print the classic Usage message
echo "Usage: $(basename "##代码##") [OPTION]..."
# In the next loop, we put in ${max_option_length} the length of the
# longest option. This way, we'll be able to calculate the offset when
# printing long descriptions that should span over several lines.
local max_option_length=1
for (( i = 0; i < ${#options[@]}; i++)); do
if [[ $max_option_length -lt ${#options[$i]} ]]; then
max_option_length=${#options[$i]}
fi
done
# We put in the following variable the total offset of descriptions
# after new-lines.
local descriptions_new_line_offset=$((${max_option_length} + ${options_offset} + ${descriptions_offset_after_longest_option}))
# The next loop is the main loop where we actually print the options with
# the corresponding descriptions.
for (( i = 0; i < ${#options[@]}; i++)); do
# First, we print the option and the offset we chose above right before it
printf -- '%*s' ${options_offset}
printf -- '%s' "${options[$i]}"
# Here we start tracking through out this loop the current index of the
# char on the terminal window. This is necessary because in the process
# of printing the descriptions' words we'll be able to know how not to
# span over the defined maximum length or not to split words when
# hitting ${COLUMNS}
local current_char_index=$((${options_offset} + ${#options[$i]}))
# We calculate the offset which should be given between the current
# option and the start of it's description. This is different for every
# option because every option has a different length but they all must
# be aligned according to the longest option's length and the offsets
# we chose above
local current_description_offset=$((${max_option_length} - ${#options[$i]} + ${descriptions_offset_after_longest_option}))
# We print this offset before printing the description
printf -- '%*s' ${current_description_offset}
# Updating the current_char_index
current_char_index=$((${current_char_index} + ${current_description_offset}))
# We put in a temporary variable the current description from the array
local current_description="${descriptions[$i]}"
# We divide the current_description to an array with the description's
# words as the array's elements. This is necessary so we can print the
# description without spliting words
IFS=' ' read -r -a description_words <<< "${current_description}"
# We start a loop for every word in the descriptions words array
for (( j = 0; j < ${#description_words[@]}; j++)); do
# We update the current char index before actually printing the
# next word in the description because of the condition right
# afterwards
current_char_index=$((${current_char_index} + ${#description_words[$j]} + 1))
# We check if the index we will reach will hit the maximum limit we
# chose in the beginning or the number of ${COLUMNS} our terminal
# gives us
if [[ ${current_char_index} -le ${COLUMNS} ]] && [[ ${current_char_index} -le ${maximum_descriptions_length} ]]; then
# If we don't hit our limit, print the current word
printf -- '%s ' ${description_words[$j]}
else
# If we've hit our limit, print a new line
printf -- '\n'
# Print a number of spaces equals to the offset we need to give
# according to longest option we have and the other offsets we
# defined above
printf -- '%*s' ${descriptions_new_line_offset}
# print the next word in the new line
printf -- '%s ' ${description_words[$j]}
# Update the current char index
current_char_index=$((${descriptions_new_line_offset} + ${#description_words[$j]}))
fi
done
# print a new line between every option and it's description
printf '\n'
done
Note that there are "tabs" in front of the "cat", and subsequent lines - HTML formatting here is likely not going to allow you to cut-n-paste the example.
请注意,在“cat”和后续行之前有“选项卡” - 此处的 HTML 格式可能不允许您剪切粘贴示例。
Note how the terminating "EOF" is left justified.
注意终止的“EOF”是如何左对齐的。
回答by Doron Behar
I think that a truly perfect solution for this kind of task should be more complicated than that. In most shells, the environment variable echo ${COLUMNS}
can be used to know in a script the width of the terminal window.
我认为对于此类任务的真正完美解决方案应该比这更复杂。在大多数 shell 中,环境变量 echo${COLUMNS}
可用于在脚本中了解终端窗口的宽度。
I've created a simple usage function for a script I wrote which takes ${COLUMNS}
into consideration. It is explained as much as possible in the comments:
我为我编写的脚本创建了一个简单的使用函数,它考虑${COLUMNS}
到了这一点。在评论中尽可能多地解释: