长话短说,我需要编写一个shell脚本。该脚本将采用单个命令行参数,该参数将是目录路径。 然后,该脚本将读取该目录中的每个文件并将其输出到标准输出;输出将以HTML格式显示。
文件将采用以下格式:
owner sysadmin group
admin ajr
loc S-309
ser 18r97
comment noisy fan
到目前为止我所拥有的:
PATH=/bin:/usr/bin
cd "$@"
if [ test $? -ne 0]
then
exit 1
fi
filenames=$(ls "$@")
for i in $filenames
do
while read item value
do
if [ $item="owner" ] || [ $item="admin" ] || [ $item="loc" ] || [ $item="ser"]
then
a[$item]=$value
fi
done < i
done
echo '<html>'
echo '<body>'
echo '<table border=1>'
echo '<tr><th>hostname</th><th>location</th><th>Admin</th><th>Serial Number</th><th>owner</th><tr>'
for i in filename
do
echo '<tr><td>'$i'</td><td>'${i[loc]}'</td><td>${i[admin]}'</td><td>'${i[ser]}'</td><td>'${i[owner]}'</td><tr>'
done
echo
echo '</table>'
echo '</body>'
echo '</html>'
HTML不是我主要关注的问题,因为我只是遵循给定的格式,每个值介于两者之间。但是,我收到一个错误,我不明白为什么:
invrep: line 10: i: no such file or directory
但是我在循环中使用它。为什么它会给我这个错误?
另外要确认,我使用的目录存在;我不确定这是否与任何事情有关。
答案 0 :(得分:3)
警告Lector :问题中的代码已被编辑。我评论过的代码可能不是你能看到的代码。
不直接问题(chepner在他的comment中)被诊断出来,但是:
cd "$@"
if [ test $? -ne 0]
then
exit 1
fi
有各种各样的问题。您没有验证只有一个参数,并且您传递了给cd
的所有参数,这些参数可能只是静静地忽略了剩余。 test
行应使用[
或test
,但不能同时使用两者。如果您使用[
,则最后一个参数必须为]
,因此您错过了一个空格:
if test $? -ne 0
if [ $? -ne 0 ]
但是,您可以通过以下方式缩短该段:
cd "$@" || exit 1
(或者你可以放弃1,尽管我会留在那里)。
您可能需要考虑:
case $# in
1) cd "$1" || exit 1;;
*) echo "Usage: $0 directory" >&2; exit 1;;
esac
这将验证是否传递了一个参数,并且它命名了一个可以cd
到的目录。
您的循环代码也存在问题。一旦你解决了问题,while
循环应该从"$i"
重定向:
filenames=$(ls "$@")
for i in $filenames
do
while read item value
do
if [ $item="owner" ] || [ $item="admin" ] || [ $item="loc" ] || [ $item="ser"]
then
a[$item]=$value
fi
done < $i
# Print HTML here!! Not after this loop
done
你的HTML循环也有很多问题 - 特别是使用$i
作为数组而不是$a
。
PATH=/bin:/usr/bin
case $# in
1) cd "$1" || exit 1;;
*) echo "Usage: $0 directory" >&2; exit 1;;
esac
echo '<html>'
echo '<body>'
echo '<table border=1>'
echo '<tr><th>hostname</th><th>location</th><th>Admin</th><th>Serial Number</th><th>owner</th><tr>'
filenames=$(ls "$@")
for i in $filenames
do
while read item value
do
if [ $item="owner" ] || [ $item="admin" ] || [ $item="loc" ] || [ $item="ser"]
then
a[$item]=$value
fi
done < $i
echo "<tr><td>$i</td><td>${a[loc]}</td><td>${a[admin]}</td><td>${a[ser]}</td><td>${a[owner]}</td><tr>"
done
echo '</table>'
echo '</body>'
echo '</html>'
这仍然无法解决使用ls
生成文件名列表的问题。为此,给定脚本的其余部分,完全丢失filenames
并使用for file in *
代替。然后,您还需要在I / O重定向中引用$i
。
PATH=/bin:/usr/bin
case $# in
1) cd "$1" || exit 1;;
*) echo "Usage: $0 directory" >&2; exit 1;;
esac
echo '<html>'
echo '<body>'
echo '<table border=1>'
echo '<tr><th>hostname</th><th>location</th><th>Admin</th><th>Serial Number</th><th>owner</th><tr>'
for i in *
do
while read item value
do
if [ $item = "owner" ] || [ $item = "admin" ] ||
[ $item = "loc" ] || [ $item="ser"]
then
a[$item]=$value
fi
done < "$i"
echo "<tr><td>$i</td><td>${a[loc]}</td><td>${a[admin]}</td><td>${a[ser]}</td><td>${a[owner]}</td><tr>"
done
echo '</table>'
echo '</body>'
echo '</html>'
(在循环中if
语句中也修复了间距。代码仍然不是很优雅,但它与原始代码有些相关。)
答案 1 :(得分:2)
filenames=$(ls "$@")
是错误的,任何人都不应该使用。请参阅http://mywiki.wooledge.org/BashPitfalls中的第一个条目,或整个页面http://mywiki.wooledge.org/ParsingLs。
如果您的参数列表是一组目录,则内部循环看起来更像是这样:
declare -A a
for dir in "$@"; do
for i in "$dir/"*; do
while read -r item value; do
case $item in
owner|admin|loc|ser)
a[$item]=$value
;;
esac
done <"$i"
done
done