如何在 bash 中连接如下单词

如何在 bash 中连接如下单词

我在 Linux 机器上有一个文件words.txt,包含以下几行。如何重复每个字符串userapplebanana,并向它们附加 1 到 4 之间的数字?

user
apple
banana

预期输出:

user1
user2
user3
user4
apple1
apple2
apple3
apple4
banana1
banana2
banana3
banana4

我尝试了以下方法,但只适用于 1 个字符串。

seq 1 4 | awk {'print $0 "user"'}

答案1

awk标准工具箱可能是您最好的选择。

awk -v min=1 -v max=4 -v increment=1 '
  {for (i = min; i <= max; i += increment) print $0 i}' words.txt

借助 GNU 工具,从以下内容中汲取灵感@JJoao 获取两个文件行的笛卡尔积的方法

join -t $'\n' -j2 -o1.1,2.1 words.txt <(seq 4) | paste -d '\0' - -

我们在第二个字段上加入words.txt和输出的地方seq 4,但是这里由于我们将字段分隔符定义为换行符,所以不能有第二个字段,或者换句话说,两个文件的每一行的第二个字段都是空的,所以我们最终将所有东西结合在一起。

答案2

sed 's/.*/&1\n&2\n&3\n&4/' words.txt

我们正在替换(s命令)每行 ( .*) 上的所有内容,整个匹配 ( &) 多次出现,并添加了文字数字和换行符。

答案3

使用普通的 bash:

while IFS= read -r word; do printf "${word}%d\\n" {1..4}; done < words.txt

但是,将变量放入 printf 格式字符串中会使其容易受到意外字符的影响。例如:

$ cat words.txt
with \n newline
with %s directive

$ while IFS= read -r word; do printf "${word}%d\\n" {1..4}; done < words.txt
with
 newline1
with
 newline2
with
 newline3
with
 newline4
with 1 directive2
with 3 directive4

反斜杠序列将被解释,并且%指令将被遵守。为了保护这一点,简单的单行解决方案变为:

while IFS= read -r word; do
    tmp1=${word//%/%%}
    tmp2=${tmp1//\\/\\\\}
    printf "${tmp2}%d\\n" {1..4}
done < words.txt

哪个输出

with \n newline1
with \n newline2
with \n newline3
with \n newline4
with %s directive1
with %s directive2
with %s directive3
with %s directive4

答案4

如果你的文件确实只有 4 行长,你可以做一些简单的事情,比如:

$ while read word; do seq 1 4 | awk -v w="$word" '{print w$0}'; done < words.txt 
user1
user2
user3
user4
apple1
apple2
apple3
apple4
banana1
banana2
banana3
banana4

这不是一个好主意使用 shell 来做这样的事情,所以这里有一个原生的 GNU awk(因为它保持原始顺序)解决方案:

$ gawk '{ words[$0] }END{for (word in words){ for(i=1;i<5;i++){printf "%s%d\n",word,i}}}' words.txt 
user1
user2
user3
user4
apple1
apple2
apple3
apple4
banana1
banana2
banana3
banana4

这种awk方法需要将整个文件读入内存。史蒂芬的回答是一种更好的解决方案,我建议您改用该解决方案。

相关内容