我有一个带有换行符分隔字符串的文本文件。我的问题是按如下方式处理每一行:使用空格作为分隔符来打乱标记的顺序。
例如:
输入:
A B C
输出:
C A B
重复运行命令/脚本当然应该提供不同的顺序。
我当前的解决方案(对于单个文本行):
$ cat <file> | tr " " "\n" | shuf | tr "\n" " "
是否有一个很好的(更好的)命令行组合来处理多行文本文件?
答案1
POSIXly,您可以相对有效地完成此操作(当然比为每一行输入awk
运行至少一个 GNU 实用程序更有效),如下所示:shuf
awk '
BEGIN {srand()}
{
for (i = 1; i <= NF; i++) {
r = int(rand() * NF) + 1
x = $r; $r = $i; $i = x
}
print
}' < your-file
(请注意,在大多数awk
实现中,在同一秒内运行同一命令两次可能会得到相同的结果,因为使用的默认随机种子srand()
通常基于当前纪元时间(以秒为单位))。
答案2
您的原始命令可以简化为
shuf -e A B C | tr "\n" " " && echo ""
或者
shuffled=( $(shuf -e A B C) ) ; echo ${shuffled[*]}
我认为这不那么麻烦,而且从我的基本测试来看也更快。
如果您有一个文件~/test
包含
A B C
D E F
您可以使用以下命令打乱并回显每一行
while IFS= read -r line; do shuffled=( $(shuf -e $line) ) ; echo ${shuffled[*]} ; done < ~/test
或以脚本形式:
#!/bin/bash
while IFS= read -r line
do shuffled=( $(shuf -e $line) )
echo ${shuffled[*]}
done < ~/test
您可能想要替换~/test
为$1
以将参数传递给脚本的位置。
结果:
B C A
G E F
这是如何运作的:
shuf -e
按空格和换行符分割..但这只是因为它将 ABC 视为三个参数。
所以
shuf -e A B C
会打乱AB和C的顺序,但shuf -e "A B C"
不会打乱AB和C的顺序
我们可以使用它将每一行读入一个数组,然后使用 再次打印出来echo
。
while IFS= read -r line;
$line
当每一行传递到此循环时,将其读入<
。
do shuffled=( $(shuf -e $line) )
$shuffled
通过字面扩展shuf -e $line
为,从变量中的每一行创建一个数组shuf -e A B C
。
echo ${shuffled[*]}
回显我们的数组,默认情况下打印每个元素之间有空格
< ~/test
将线路输入~/test
到我们的循环中。
答案3
给定
$ cat file
A B C
D E F
G H I J
然后使用shuffle
perl 的 List::Util 模块:
$ perl -MList::Util=shuffle -alpe '$_ = join " ", shuffle @F' file
C B A
E D F
I J G H
使用 bashread -a
和shuf
(但效率非常低,因为它每行运行 3 个实用程序,其中 2 个不是内置的):
$ while read -ra arr; do shuf -e -- "${arr[@]}" | paste -sd ' ' -; done < file
A C B
F E D
J I G H
答案4
要将参数作为一行传递:
shuf -e one two three four
就是你所需要的。
shuf -e $(cat <file>) | tr "\n" " "
对于只有一行的文件,如您的示例所示。
对于多行:
while read line; do shuf -e $line | tr "\n" " " && echo \n; done < <file>