Linux用户名/etc/passwd列表

Linux用户名/etc/passwd列表,linux,sorting,grep,etcpasswd,Linux,Sorting,Grep,Etcpasswd,我想打印/etc/passwd中的最长和最短用户名。如果我运行下面的代码,它可以运行最短的(head-1),但不能运行(sort-n | tail-1 | awk'{print$2})。有人能帮我找出问题所在吗 #/bin/bash grep-Eo'^([^::]+'/etc/passwd| 读名字的时候 做 echo${#NAME}${NAME} 完成| 排序-n | head-1 | awk'{print$2}' 排序-n | tail-1 | awk'{print$2}' 问题在于,当您真

我想打印
/etc/passwd
中的最长和最短用户名。如果我运行下面的代码,它可以运行最短的(
head-1
),但不能运行(
sort-n | tail-1 | awk'{print$2}
)。有人能帮我找出问题所在吗

#/bin/bash
grep-Eo'^([^::]+'/etc/passwd|
读名字的时候
做
echo${#NAME}${NAME}
完成|
排序-n | head-1 | awk'{print$2}'
排序-n | tail-1 | awk'{print$2}'

问题在于,当您真正需要一条管道时,您只有两条管道。所以你有
grep |边读边做。。。完成|排序|头| awk
排序|尾| awk
:第一个
排序
有一个输入(即
while
循环)-第二个
排序
没有。所以脚本挂起是因为您的第二个排序没有输入:或者更确切地说,它有输入,但它是STDIN

有多种解决方法:

  • while
    循环的输出保存到临时文件中,并将其用作
    排序
    命令的输入
  • 重复你的while循环
  • 用awk做头部和尾部

前两个涉及在密码文件上迭代两次,这可能没问题——取决于您最终要做什么。但是使用一个小的awk脚本,它可以通过
BEGIN
END
块为您提供第一行和最后一行。

如果您希望头部和尾部都来自同一个输入,您可能需要类似
sed-e1b-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'
问题是:

管道通过第一个sort-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}

您只需要:

$ 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
$awk-F:'
NR==1{min=max=$1}
长度($1)>长度(max){max=$1}
长度($1)

不需要显式循环、管道或多个命令。

虽然您已经有了很好的答案,但您也可以使用POSIX shell来实现您的目标,而无需使用shell本身提供的参数扩展和字符串长度(请参阅:)。例如,您可以执行以下操作:

#!/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"
使用管道/头/尾/awk或壳体本身都可以。有其他选择是好的


(注意:如果您有多个相同长度的用户,这只会选择第一个,如果您想保存所有名称,可以使用临时文件,并使用
-le
-ge
进行比较。)

不知怎的,您总是有另一块宝藏。干得好,艾德。我相信这其实更容易。非常感谢埃德,不客气。是的,它更简单、更健壮(考虑到各种输入文件内容,您当前接受的解决方案将以有趣的方式失败)、更高效、更可移植,等等——也就是说,与带有一堆管道和其他工具的shell循环相比,它在各方面都更好。有关shell循环的一些(但不是全部)问题,请参阅,然后查看下一步要做什么。
$ sh cketcpw.sh
shortest ( 2): at
longest  (17): systemd-bus-proxy