I always write some magic numbers in my interactive shells and shell scripts.
For instance, If I want to list my users's names and shells, I'll write
cut --delimiter=: --fields=1,7 /etc/passwd
There exist two magic-numbers 1
,7
. And there are more and more magic-numbers in other circumstances.
How to avoid magic-numbers in interactive shells and shell scripts?
Our teacher told us using cut -d: -f1,7 /etc/passwd
. But for new linux-users, they don't konw what's meaning of d
,f
,1
,7
.(not just for new linux-users,the whole system has so many configuration files that it is not easy for a person to remember every magic-numbers)
So, in interactive shells, we can use --delimiter
, --fields
,and the bash repl(or zsh,fish) has good tab completion to it.
How about the 1
and 7
? In shell scripts, It's a good method to declare some const variables like LoginField=1 and ShellField=7 after reading the man 5 passwd
. But when some one is writing in the interactive shells, it's not a good idea to open a new window and search the constants of LoginField=1
,ShellField=7
and define it. how to using some thing like tab completion to simplify operations?
答案 0 :(得分:1)
Use variables:
LoginField=1 ShellField=7
cut --delimiter=: --fields="$LoginField,$ShellField" /etc/passwd
答案 1 :(得分:1)
Just like in other languages - by using variables. Example:
$ username_column=1
$ shell_column=7
$ cut --delimiter=: --fields="$username_column","$shell_column" /etc/passwd
The variables may be defined at the top of the script so that can be easily modified or they can be set in an external config-like file shared by multiple scripts.
答案 2 :(得分:1)
解析/ etc / passwd的经典方法是将每列读入一个适当命名的变量:
while IFS=: read name passwd uid gid gecos home shell _; do
...
done < /etc/passwd
答案 3 :(得分:0)
Use export:
export field_param="1,7"
(you can put it .bashrc file to have configured each time shell session is started). This export can be part of .sh script. It's a good practice to put them in the head/top of the file.
Then:
cut --delimiter=: --fields=$field_param /etc/passwd
This way you will need to edit the magic number in the only location.
答案 4 :(得分:0)
Continuing from my comment, it's hard to tell exactly what you are asking. If you just want to give meaningful variable names, then do as shown in the other answers.
If however you want to be able to specify which fields are passed to cut
from the command line, then you can use the positional parameters $1
and $2
to pass those values into your script.
You need to validate that two inputs are given and that both are integers. You can do that with a few simple tests, e.g.
#!/bin/bash
[ -n "$1" ] && [ -n "$2" ] || { ## validate 2 parameters given
printf "error: insufficient input\nusage: %s field1 field2\n" "${0##*/}"
exit 1
}
## validate both inputs are integer values
[ "$1" -eq "$1" >/dev/null 2>&1 ] || {
printf "error: field1 not integer value '%s'.\n" "$1"
exit 1
}
[ "$2" -eq "$2" >/dev/null 2>&1 ] || {
printf "error: field2 not integer value '%s'.\n" "$2"
exit 1
}
cut --delimiter=: --fields=$1,$2 /etc/passwd
Example Use/Output
$ bash fields.sh
error: insufficient input
usage: fields.sh field1 field2
$ bash fields.sh 1 d
error: field2 not integer value 'd'.
$ bash fields.sh 1 7
root:/bin/bash
bin:/usr/bin/nologin
daemon:/usr/bin/nologin
mail:/usr/bin/nologin
ftp:/usr/bin/nologin
http:/usr/bin/nologin
uuidd:/usr/bin/nologin
dbus:/usr/bin/nologin
nobody:/usr/bin/nologin
systemd-journal-gateway:/usr/bin/nologin
systemd-timesync:/usr/bin/nologin
systemd-network:/usr/bin/nologin
systemd-bus-proxy:/usr/bin/nologin
<snip>
Or if you choose to look at fields 1
and 3
, then all you need do is pass those as the parameters, e.g.
$ bash fields.sh 1 3
root:0
bin:1
daemon:2
mail:8
ftp:14
http:33
uuidd:68
dbus:81
nobody:99
systemd-journal-gateway:191
systemd-timesync:192
systemd-network:193
systemd-bus-proxy:194
<snip>
Look things over and let me know if you have further questions.
答案 5 :(得分:0)
为人类可读的标题名称刮取man 5 passwd
的输出:
declare $(man 5 passwd |
sed -n '/^\s*·\s*/{s/^\s*·\s*//;y/ /_/;p}' |
sed -n 'p;=' | paste -d= - - )
参见&#34; 工作原理&#34;在下面做什么,然后运行:
cut --delimiter=: \
--fields=${login_name},${optional_user_command_interpreter} /etc/passwd
输出指定的/etc/passwd
字段。
工作原理。
描述man
的{{1}}页面包含标题名称的项目符号列表。使用 GNU /etc/passwd
查找项目符号(sed
)和前导空格,然后删除项目符号和空格,用下划线替换剩余的空格; ·
的第二个实例提供了新的行号,然后sed
标题名称为行号,其中paste
位于:
=
输出:
man 5 passwd |
sed -n '/^\s*·\s*/{s/^\s*·\s*//;y/ /_/;p}' |
sed -n 'p;=' | paste -d= - -
而login_name=1
optional_encrypted_password=2
numerical_user_ID=3
numerical_group_ID=4
user_name_or_comment_field=5
user_home_directory=6
optional_user_command_interpreter=7
会使当前shell中的那些活动。