我想打印/etc/passwd
中找到的最长和最短的用户名。如果我运行下面的代码,它适用于最短的(head -1
),但不适用于(sort -n |tail -1 | awk '{print $2}
)。谁能帮我弄清楚什么是错的?
#!/bin/bash
grep -Eo '^([^:]+)' /etc/passwd |
while read NAME
do
echo ${#NAME} ${NAME}
done |
sort -n |head -1 | awk '{print $2}'
sort -n |tail -1 | awk '{print $2}'
答案 0 :(得分:4)
问题在于:
使用第一个排序-n | head -1 |进行管道处理awk' {print $ 2}' 命令。因此,通过管道提供对第一个命令的输入并获得输出。
对于第二个命令,没有给出输入。因此,它等待键盘STDIN的输入,您可以通过键盘输入输入,然后按ctrl + D获取输出。
请运行如下代码以获得所需的输出:
#!/bin/bash
grep -Eo '^([^:]+)' /etc/passwd |
while read NAME
do
echo ${#NAME} ${NAME}
done |
sort -n |head -1 | awk '{print $2}'
grep -Eo '^([^:]+)' /etc/passwd |
while read NAME
do
echo ${#NAME} ${NAME}
done |
sort -n |tail -1 | awk '{print $2}
'
答案 1 :(得分:2)
您只需要:
$ awk -F: '
NR==1 { min=max=$1 }
length($1) > length(max) { max=$1 }
length($1) < length(min) { min=$1 }
END { print min ORS max }
' /etc/passwd
不需要显式循环或管道或多个命令。
答案 2 :(得分:1)
问题是,当你真的需要一个时,你只有两个管道。因此,您有grep | while read do ... done | sort | head | awk
和sort | tail | awk
:第一个sort
有一个输入(即while
循环) - 第二个sort
没有。所以脚本是挂起的,因为你的第二种类型没有输入:或者更确切地说它是,但它是STDIN。
有多种解决方法:
while
循环的输出保存到临时文件,并将其用作sort
命令的输入前两个涉及迭代密码文件两次,这可能没问题 - 取决于你最终要做的事情。但是使用一个小的awk脚本,这可以通过BEGIN
和END
块为您提供第一行和最后一行。
答案 3 :(得分:1)
虽然您已经有了很好的答案,但您也可以使用POSIX shell来完成您的目标,而无需任何管道使用shell提供的参数扩展和字符串长度本身(见:POSIX shell specifiction)。例如,您可以执行以下操作:
#!/bin/sh
sl=32;ll=0;sn=;ln=; ## short len, long len, short name, long name
while read -r line; do ## read each line
u=${line%%:*} ## get user
len=${#u} ## get length
[ "$len" -lt "$sl" ] && { sl="$len"; sn="$u"; } ## if shorter, save len, name
[ "$len" -gt "$ll" ] && { ll="$len"; ln="$u"; } ## if longer, save len, name
done </etc/passwd
printf "shortest (%2d): %s\nlongest (%2d): %s\n" $sl "$sn" $ll "$ln"
示例使用/输出
$ sh cketcpw.sh
shortest ( 2): at
longest (17): systemd-bus-proxy
使用pipe / head / tail / awk或shell本身就可以了。有替代品是很好的。
(注意:如果您有多个相同长度的用户,这只是选择第一个,如果您想保存所有名称并使用-le
和-ge
,则可以使用临时文件比较)。
答案 4 :(得分:0)
如果您希望头部和尾部来自同一输入,则在对数据进行排序后,您可能需要sed -e 1b -e '$!d'
之类的内容,以使用sed
来获取顶行和底行。
所以你的脚本将是:
#!/bin/bash
grep -Eo '^([^:]+)' /etc/passwd |
while read NAME
do
echo ${#NAME} ${NAME}
done |
sort -n | sed -e 1b -e '$!d'
或者,更短的方式:
cut -d":" -f1 /etc/passwd | awk '{ print length, $0 }' | sort -n | cut -d" " -f2- | sed -e 1b -e '$!d'