在Bash中获得非单调增加的字段

时间:2018-06-13 13:52:01

标签: bash cut

我们说我有一个包含多个列的文件,我想获得几个字段,但它们可能没有按顺序增加。字段索引在数组中,索引可以是任何顺序或根本不是顺序,索引的数量是未知的,例如:

arr=(1 3 2)   #indexes, unknown length
echo 'c1 c2 c3' | cut -d " " -f "${arr[*]}"

输出是

c1 c2 c3

但我想要

c1 c3 c2

所以似乎cut在阅读之前对字段进行排序,我不想这样做。我不限于cut,可以使用任何其他命令。

但是,我只限于这个相当旧版本的bash:

GNU bash, version 2.05b.0(1)-release (i586-suse-linux)
Copyright (C) 2002 Free Software Foundation, Inc.

编辑解答感谢Benjamin W和Glenn Jackman

echo "1 2 3" | awk -v fields="${arr[*]}" 'BEGIN{ n = split(fields,f) } { for (i=1; i<=n; ++i) printf "%s%s", $f[i], (i<n?OFS:ORS) }'

使用&#39; *&#39;引用数组非常重要。而不是&#39; @&#39;。

4 个答案:

答案 0 :(得分:1)

这可能适用于bash 2.05,也可能不适用:

arr=(1 3 2)
set -f                         # disable filename generation
while read line; do
    set -- $line               # unquoted: taking advantage of word splitting, 
                               # store the words as positional parameters
    for i in "${arr[@]}"; do
        printf "%s " "${!i}"   # indirect variable expansion
    done
    echo
done < file

或者,perl

$ cat file
c1 c2 c3
$ perl -slane '
    BEGIN {@a = map {$_ - 1} split " ", $arr} 
    print join " ", @F[@a]
' -- -arr="${arr[*]}" file
c1 c3 c2

答案 1 :(得分:1)

使用awk

$ arr=(1 3 2)
$ echo 'c1 c2 c3' | awk -v arr="${arr[*]}" '
    BEGIN {
        split(arr, idx," ");
    } 
    {
        for(i=1; i<=length(idx); ++i) 
            printf("%s ",$idx[i])} ;
    END {
        printf("\n")
    }
'
  1. 首先,将arr拆分为' '并分配给idx
  2. 然后,根据每个索引i
  3. 进行打印

答案 2 :(得分:0)

使用FreeASlot

GeneralParkingLot

顺序由命令行传递的DowntownParkingLot变量给出。假设此变量包含输入文件中可用的空格分隔值。

awk块中,数组$ cat file a b c d a b c d a b c d a b c d $ awk -v ord="1 4 3 2" 'BEGIN { split(ord, order, " ") } { split($0, line, FS) for (i = 1; i <= length(order); ++i) $i = line[order[i]] print }' file a d c b a d c b a d c b a d c b 是通过在空格上拆分而从ord创建的。

在默认块中,当前输入行被分割为BEGIN上的数组order(默认为空白)。然后根据ord数组重新排列字段,然后打印出重新构建的行。

没有测试line中的传入值是否合理。如果输入具有 N 列,则必须包含从1到 N 的所有整数。

答案 3 :(得分:0)

从您的印刷品中提取您的读物,以便您可以命名零件并相应地订购。

$: cat x
c1 c2 c3
c1 c2 c3
c1 c2 c3
c1 c2 c3
c1 c2 c3
$: cut -f 1,3,2 x |
> while read a b c
> do printf "$a $c $b\n"
> done
c1 c3 c2
c1 c3 c2
c1 c3 c2
c1 c3 c2
c1 c3 c2

这会将读取循环放入bash解释器,它不像二进制文件那么快,但不需要您已经使用的其他工具。

如果你有perl,我没有看到使用awk的重点,所以如果文件足够大你需要更快的解决方案,试试这个:

perl -a -n -e 'print join " ", @F[0,2,1],"\n"' x

假设很多,并在换行前添加一个空格,但应该给你一个工作的地方开始。