代码之家  ›  专栏  ›  技术社区  ›  KamilCuk

使用空字节作为分隔符将每个参数与参数的位置号联接?

  •  0
  • KamilCuk  · 技术社区  · 6 年前

    我想用参数的位置号连接每个参数。我只想使用空字节作为分隔符。
    以下是我想要的:

    f() {
       for ((i=1;i<$(($#+1));++i)); do
         echo -n "$i"
         echo -ne "\x00"
         echo -n "${!i}"
         echo -ne "\x00"
       done
    }
    
    f a b c | hexdump -C
    00000000  31 00 61 00 32 00 62 00  33 00 63 00              |1.a.2.b.3.c.|
    0000000c
    

    不过,我想删除for循环(因为它很难看),并使用管道和/或进程替换。所以问题是:如何使用空字节作为分隔符连接两个空字节分隔的流。 我试着用浆糊:

    printf '%s\x00' "$@" | paste -z -d '\0' <(seq $# | tr '\n' '\0') -
    

    但是当调用 -d'\0' 浆糊根本不会插入分度计。在不指定delimeter的情况下,paste使用tab。有没有办法让粘贴使用空字节作为列分隔符?有没有其他实用程序可以在这里工作?

    3 回复  |  直到 6 年前
        1
  •  1
  •   rici    6 年前

    为了完整起见,只使用printf的非循环构造(但使用两次):

    printf "$(printf '%d\\000%%s\\000' $(seq $#))" "$@"
    

    内部 printf 创建预先填充序列号的格式字符串。 \000 必须防止插入字符串开头的数字合并到转义码中。

        2
  •  1
  •   chepner    6 年前

    循环不是问题,而是循环的使用。

    f () {
      local i
      for ((i=1; i<=$#; i++)); do
        printf '%d\0%s\0' "$i" "${!i}"
      done
    }
    

    或者可能

    f () {
      i=1
      for arg; do
        printf '%d\0%s\0' "$((i++))" "$arg"
      done
    }
    

    它将在任何posix shell中工作,尽管它覆盖了全局 i .

        3
  •  1
  •   anubhava    6 年前

    for loop answer by Chepner 使用非常简单,绝对能解决丑陋的问题。

    另一种方法是不使用循环:

    paste -zd $'\01' <(seq $# | tr '\n' '\0') <(printf '%s\0' "$@") | tr '\1' '\0'
    

    这个 paste 命令粘贴两个流 \01 作为列分隔符和最后一个 tr 命令转换 01 \0 (NUL)字节。