我在 Linux 机器上有一个文件words.txt
,包含以下几行。如何重复每个字符串user
、apple
和banana
,并向它们附加 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
方法需要将整个文件读入内存。史蒂芬的回答是一种更好的解决方案,我建议您改用该解决方案。