Linux 如何将主机文件作为用户的输入并将其调用到脚本中
Linux How to take hostfile as an input from user and call it into script
我正在使用下面的脚本来 ping 多个 Linux 主机,如果它通过硬编码将 hostfile
放入脚本本身,它会工作得很好,但我希望它基于用户输入。
虽然我正在使用 read
文件作为用户的输入,但那是失败的,请告诉我我在这里做错了什么。
#!/bin/bash
read -rsp $'Please Enter your hostFile name: ' target_File
echo $target_File
printf "$(date) Starting the Ping Check...."
function pingHost () {
target_host=
ping -c2 ${target_host} >/dev/null 2>&1 &&
printf "%-20s %-10s\n" "host ${target_host}" "ping SUCCESS" ||
printf "%-20s %-10s\n" "host ${target_host}" "ping FAILED"
}
#
# Variable "data" seeks the filename containing host list.
data="$(< target_File)"
for line in $data
do
pingHost ${line} &
done
wait
printf "Completed @=> $(date)"
printf "\n"
在脚本中给出 hostfile
然后它的工作方式如下..
data="$(< hostfile)" <-- this hard-coded file containing hosts
$ ./ping_parallel.bash
Sun May 22 10:55:24 IST 2022 Starting the Ping Check....
host savfav0194 ping SUCCESS
host savfav0268 ping SUCCESS
host savfav0263 ping SUCCESS
host savfav0196 ping SUCCESS
host savfav0260 ping SUCCESS
host savfav0259 ping SUCCESS
host savfav2088 ping SUCCESS
host savfav2135 ping SUCCESS
host savfav2136 ping SUCCESS
host savfav3088 ping SUCCESS
host savfav0257 ping SUCCESS
host savfav0262 ping SUCCESS
host savfav0261 ping SUCCESS
host savfav0270 ping SUCCESS
host savfav0255 ping SUCCESS
host savfav0265 ping SUCCESS
host savfav0266 ping FAILED
Completed @=> Sun May 22 10:55:26 IST 2022
尝试用户输入时失败:
Please Enter your hostFile name: target_File
Sun May 22 10:58:54 IST 2022 Starting the Ping Check...../ping_parallel.bash: line 22: target_File: No such file or directory
Completed @=> Sun May 22 10:58:54 IST 2022
你说那行不通(将 data=$(< target_File)
更改为 data=$(< $target_File)
)
$ target_File=hosts.txt
$ data=$(< target_File)
bash: target_File: No such file or directory
$ echo $data
$ data=$(< $target_File)
$ echo $data
google.com amazon.com
# seems to be fine
$ for x in $data; do echo pingit $x; done
pingit google.com
pingit amazon.com
阅读
$ read target_File
hosts.txt
$ data=$(< $target_File)
$ echo $data
google.com amazon.com
如评论中所述,也是使用 while
而不是 for
的良好做法,请在此处参考 bash manual。
我刚刚用 while
修改了它,希望它适合你!
#!/bin/bash
read -p $'Please Enter your hostFile name: ' target_File
printf "$(date) Starting the Ping Check...."
function pingHost () {
target_host=
ping -c2 ${target_host} >/dev/null 2>&1 &&
printf "%-20s %-10s\n" "host ${target_host}" "ping SUCCESS" ||
printf "%-20s %-10s\n" "host ${target_host}" "ping FAILED"
}
while read -r line;
do
pingHost $line &
done < $target_File
wait
printf "Completed @=> $(date)"
printf "\n"
对脚本稍作修改:
#!/bin/bash
read -rp $'Please Enter your hostFile name: ' target_File
# Don't use variables in the printf format string. Use printf '..%s..' "$(date)".
printf "Starting the Ping Check %s ....\n" "$(date)"
# You Can Just use function name hence its your choice, i just removed.
# pingHost i changed to "icmp_echo" as i used that
# function pingHost () {
icmp_echo () {
target_host=
ping -c2 "${target_host}" >/dev/null 2>&1 &&
printf "%-32s %-10s\n" "host ${target_host}" "ping SUCCESS" ||
printf "%-32s %-10s\n" "host ${target_host}" "ping FAILED"
}
# Use a while loop and the read command. Where The -r option to read prevents backslash interpretation.By default,read modifies each line read,
# by removing all leading and trailing whitespace characters (spaces and tabs, if present in IFS).If that is not desired, the IFS variable may
# be cleared
while IFS= read -r line
do
icmp_echo "$line" &
# Double quote to prevent globbing and word splitting.
done < "$target_File"
wait
# Don't use variables in the printf format string. Use printf '..%s..' "$(date)".
printf "Completed @=> %s" "$(date)"
printf "\n"
继续评论和请求答复,您的脚本有许多小问题您应该解决。首先,请始终将您的脚本粘贴到 ShellCheck 并解决所有问题,然后再发布到这里(真的很好)。
发现的其他问题(一些 material,一些形式)是:
- POSIX 函数定义就是
name() { body }
。 function
一词是 bash 主义,允许将函数定义为 function name { body }
,是的 bash 甚至可以接受组合。对于可移植脚本,始终仅使用 name() { body }
。
- 不要在
printf
format-string 中嵌入可扩展文本或变量。这就是 conversion-specifiers 的用途。不要将 fixed-text 与您通过 format-specifiers 发送的字符串中的变量组合在 format-string 中。固定文本进入 format-string 本身,例如
不
echo $target_File
printf "$(date) Starting the Ping Check...."
#...
printf "%-20s %-10s\n" "host ${target_host}" "ping SUCCESS"
改为
printf "%s\n%s Starting ping check...\n" "hostsfile" "$(date)"
#...
printf "host %-20s ping SUCCESS\n" ""
- 验证,验证,验证 - 特别是 user-input 和文件名
- 不要用
list=$(<file)
和for i in "$list"; do ... done
,而是while read -r line; do ... done < file
把所有的部分放在一起,你可以做类似下面的事情:
#!/bin/bash --norc
## function
pinghost() {
## validate argument provided
[ -z "" ] && {
printf "error: no host provided.\n" >&2
return;
}
if ping -c2 "" >/dev/null 2>&1 ; then ## check ping success / failure
printf "host %-20s ping SUCCESS\n" "" ## use fixed-text / specifiers properly
else
printf "host %-20s ping FAILED\n" ""
fi
}
## destination hosts, validate filename given and file exists and has non-zero size
if [ -n "" ] && [ -s "" ]; then
hostsfile=""
else
printf "error: hostsfile argument required to non-zero size file.\n" >&2
exit 1
fi
## never embed expandable output in the printf format-string, use proper spedifiers
# printf "$(date) Starting the Ping Check...."
printf "%s\n%s Starting ping check...\n" "$hostsfile" "$(date)"
## loop over each line in hosts file
while read -r host; do
pinghost "$host" ## no sense in backgrounding just to wait
done < "$hostsfile"
printf "Completed @=> %s\n" "$(date)" ## the '\n' belongs in the format-string
如果您还有其他问题,请告诉我。
我正在使用下面的脚本来 ping 多个 Linux 主机,如果它通过硬编码将 hostfile
放入脚本本身,它会工作得很好,但我希望它基于用户输入。
虽然我正在使用 read
文件作为用户的输入,但那是失败的,请告诉我我在这里做错了什么。
#!/bin/bash
read -rsp $'Please Enter your hostFile name: ' target_File
echo $target_File
printf "$(date) Starting the Ping Check...."
function pingHost () {
target_host=
ping -c2 ${target_host} >/dev/null 2>&1 &&
printf "%-20s %-10s\n" "host ${target_host}" "ping SUCCESS" ||
printf "%-20s %-10s\n" "host ${target_host}" "ping FAILED"
}
#
# Variable "data" seeks the filename containing host list.
data="$(< target_File)"
for line in $data
do
pingHost ${line} &
done
wait
printf "Completed @=> $(date)"
printf "\n"
在脚本中给出 hostfile
然后它的工作方式如下..
data="$(< hostfile)" <-- this hard-coded file containing hosts
$ ./ping_parallel.bash
Sun May 22 10:55:24 IST 2022 Starting the Ping Check....
host savfav0194 ping SUCCESS
host savfav0268 ping SUCCESS
host savfav0263 ping SUCCESS
host savfav0196 ping SUCCESS
host savfav0260 ping SUCCESS
host savfav0259 ping SUCCESS
host savfav2088 ping SUCCESS
host savfav2135 ping SUCCESS
host savfav2136 ping SUCCESS
host savfav3088 ping SUCCESS
host savfav0257 ping SUCCESS
host savfav0262 ping SUCCESS
host savfav0261 ping SUCCESS
host savfav0270 ping SUCCESS
host savfav0255 ping SUCCESS
host savfav0265 ping SUCCESS
host savfav0266 ping FAILED
Completed @=> Sun May 22 10:55:26 IST 2022
尝试用户输入时失败:
Please Enter your hostFile name: target_File
Sun May 22 10:58:54 IST 2022 Starting the Ping Check...../ping_parallel.bash: line 22: target_File: No such file or directory
Completed @=> Sun May 22 10:58:54 IST 2022
你说那行不通(将 data=$(< target_File)
更改为 data=$(< $target_File)
)
$ target_File=hosts.txt
$ data=$(< target_File)
bash: target_File: No such file or directory
$ echo $data
$ data=$(< $target_File)
$ echo $data
google.com amazon.com
# seems to be fine
$ for x in $data; do echo pingit $x; done
pingit google.com
pingit amazon.com
阅读
$ read target_File
hosts.txt
$ data=$(< $target_File)
$ echo $data
google.com amazon.com
如评论中所述,也是使用 while
而不是 for
的良好做法,请在此处参考 bash manual。
我刚刚用 while
修改了它,希望它适合你!
#!/bin/bash
read -p $'Please Enter your hostFile name: ' target_File
printf "$(date) Starting the Ping Check...."
function pingHost () {
target_host=
ping -c2 ${target_host} >/dev/null 2>&1 &&
printf "%-20s %-10s\n" "host ${target_host}" "ping SUCCESS" ||
printf "%-20s %-10s\n" "host ${target_host}" "ping FAILED"
}
while read -r line;
do
pingHost $line &
done < $target_File
wait
printf "Completed @=> $(date)"
printf "\n"
对脚本稍作修改:
#!/bin/bash
read -rp $'Please Enter your hostFile name: ' target_File
# Don't use variables in the printf format string. Use printf '..%s..' "$(date)".
printf "Starting the Ping Check %s ....\n" "$(date)"
# You Can Just use function name hence its your choice, i just removed.
# pingHost i changed to "icmp_echo" as i used that
# function pingHost () {
icmp_echo () {
target_host=
ping -c2 "${target_host}" >/dev/null 2>&1 &&
printf "%-32s %-10s\n" "host ${target_host}" "ping SUCCESS" ||
printf "%-32s %-10s\n" "host ${target_host}" "ping FAILED"
}
# Use a while loop and the read command. Where The -r option to read prevents backslash interpretation.By default,read modifies each line read,
# by removing all leading and trailing whitespace characters (spaces and tabs, if present in IFS).If that is not desired, the IFS variable may
# be cleared
while IFS= read -r line
do
icmp_echo "$line" &
# Double quote to prevent globbing and word splitting.
done < "$target_File"
wait
# Don't use variables in the printf format string. Use printf '..%s..' "$(date)".
printf "Completed @=> %s" "$(date)"
printf "\n"
继续评论和请求答复,您的脚本有许多小问题您应该解决。首先,请始终将您的脚本粘贴到 ShellCheck 并解决所有问题,然后再发布到这里(真的很好)。
发现的其他问题(一些 material,一些形式)是:
- POSIX 函数定义就是
name() { body }
。function
一词是 bash 主义,允许将函数定义为function name { body }
,是的 bash 甚至可以接受组合。对于可移植脚本,始终仅使用name() { body }
。 - 不要在
printf
format-string 中嵌入可扩展文本或变量。这就是 conversion-specifiers 的用途。不要将 fixed-text 与您通过 format-specifiers 发送的字符串中的变量组合在 format-string 中。固定文本进入 format-string 本身,例如
不
echo $target_File
printf "$(date) Starting the Ping Check...."
#...
printf "%-20s %-10s\n" "host ${target_host}" "ping SUCCESS"
改为
printf "%s\n%s Starting ping check...\n" "hostsfile" "$(date)"
#...
printf "host %-20s ping SUCCESS\n" ""
- 验证,验证,验证 - 特别是 user-input 和文件名
- 不要用
list=$(<file)
和for i in "$list"; do ... done
,而是while read -r line; do ... done < file
把所有的部分放在一起,你可以做类似下面的事情:
#!/bin/bash --norc
## function
pinghost() {
## validate argument provided
[ -z "" ] && {
printf "error: no host provided.\n" >&2
return;
}
if ping -c2 "" >/dev/null 2>&1 ; then ## check ping success / failure
printf "host %-20s ping SUCCESS\n" "" ## use fixed-text / specifiers properly
else
printf "host %-20s ping FAILED\n" ""
fi
}
## destination hosts, validate filename given and file exists and has non-zero size
if [ -n "" ] && [ -s "" ]; then
hostsfile=""
else
printf "error: hostsfile argument required to non-zero size file.\n" >&2
exit 1
fi
## never embed expandable output in the printf format-string, use proper spedifiers
# printf "$(date) Starting the Ping Check...."
printf "%s\n%s Starting ping check...\n" "$hostsfile" "$(date)"
## loop over each line in hosts file
while read -r host; do
pinghost "$host" ## no sense in backgrounding just to wait
done < "$hostsfile"
printf "Completed @=> %s\n" "$(date)" ## the '\n' belongs in the format-string
如果您还有其他问题,请告诉我。