纯的巴什

纯的巴什

我正在学习 Bash 脚本,但我正在努力解决这个问题。给定来自 的一堆行STDIN,首先按行的长度按升序对它们进行排序。然后,如果有任何行具有相同的字符数,则按行中包含的非空白字符数对它们进行排序(也是按升序排列)。

我尝试过几种不同的方法,但我通常会陷入 Bash 的一些特性中。

这是我到目前为止所得到的:

#!/bin/bash

sorted=()
while IFS='' read -r line; do
    length=${#line}
    if [[ ${sorted[$length]} == "" ]] ; then
        sorted[$length]="$line"
    else
        #non unique length
        #sorted[$length]="${sorted[$length]}\n$line"
        IFS=$'\n' arr=("${sorted[$length]}")
        arr+=("$line")

        spaces=()

        for ((i=0 ; i < ${#arr[@]} ; ++i )) ; do
            spaces[$i]=$(echo "${arr[$i]}" | sed "s: : \n:g" | grep -c " ")
        done

        arr_sorted=()

        for ((i =0 ; i < ${#spaces[@]} ; i++ )) ; do
                for ((j=0 ; j < ${#arr[@]} ; i++ )) ; do

                        this_line_length=$(echo "${arr[$j]}" | sed "s: : \n:g" | grep -c " ")
                        if [[ "$this_line_length" == "${spaces[$i]}" ]] ; then
                            arr_sorted+=("${arr[$j]}")
                            unset arr[$j]
                        fi
                done
        done


    sorted[$length]="${arr_sorted[@]}"


    fi
done

我将继续猜测这远不是最好的方法。我以为我会尝试在不过度依赖 bash 内置函数的情况下实现所有内容,但现在看来毫无意义。

答案1

使用与其他相同的原则(获取行长度,有或没有空白字符,对它们进行排序,然后删除它们),但使用awk

awk '{NC = length(gensub(/[[:space:]]/, "", "g")); print length, NC, $0}' file |
  sort -nk1,2 |
  sed -r 's/^([0-9]+ ){2}//'

gensub(/[[:space:]]/, "", "g")删除该行中的所有空白字符,然后我们得到剩余字符串的长度

使用问题文本直至代码块,折叠为 80 个字符宽:

$ awk '{NC = length(gensub(/[[:space:]]/, "", "g")); print length, NC, $0}' foo | sort -nk1,2 | sed -r 's/^([0-9]+ ){2}//'


 increasing order).
Here's what I've got so far:
f the idiosyncrasies of bash.
iven a bunch of lines from STDIN, sort them first by the length of the line in i
I've tried this a couple of different ways but I usually get caught up in some o
, sort them by the number of nonblank characters contained in the lines (also in
I am working on learning bash scripting but I am struggling with this problem. G
ncreasing order. Then, if there are any lines with the same number of characters

答案2

如果您被允许使用邪恶的外部装置,例如sortcut

#! /bin/bash
while IFS= read -r line; do
    squeezed=$( tr -d '[:blank:]' <<<"$line" )
    printf '%d\t%d\t%s\n' ${#line} ${#squeezed} "$line"
done | sort -n -k 1 -k 2 | cut -f 3-

编辑:既然每个人都这样做,这里有一个解决方案perl

perl -e 'print sort { length $a <=> length $b || $a =~ y/ \t//c <=> $b =~ y/ \t//c } <>'

答案3

纯的

输入较小时,这可能比其他答案快得多,因为没有分叉!

sortByLength () { 
    local -a sorted=() sort2
    local line sline sline2 pointer
    while IFS= read -r line; do
        sorted[${#line}]+="$line."
    done
    for pointer in ${!sorted[@]} ;do
        sort2=()
        line="${sorted[pointer]}"
        while [ "$line" ]; do
            sline=${line:0:pointer}
            line=${line:pointer+1}
            sline2=${sline//[[:blank:]]}
            sort2[${#sline2}]+=${sline}$'\n'
        done
        printf "%s" "${sort2[@]}"
    done
}

因为这看起来像家庭作业,我会让你解释一下这是如何工作的......

只需 1 个叉子即可

sortByLength () {
    perl -e '
        while(<>){
            chomp;
            push @a,$_;
        };
        map {
            printf "%s\n",${$_}[2];
        } sort {
            ${$a}[0]*1000+${$a}[1] <=> ${$b}[0]*1000+${$b}[1]
        }  map {
            my $s=$_;
            s/\s//g;
            [ length($s),length($_),$s ]
        } @a;
    '
}

答案4

功能:

sortlen() { while read x ; do \
              y=`tr -d '[:blank:]' <<< "$x"` ; echo ${#x} ${#y} "$x" ; \
            done | sort -k 1g,2 -k 2g,3 | cut -d' ' -f3-; }

测试:

printf "a b c\nabcde\nabcdefg\na\nabcd\n" | sortlen

输出:

a
abcd
a b c
abcde
abcdefg

相关内容