BASH - 随机排列文件中字符串中的字符
BASH - Shuffle characters in strings from file
我有一个具有以下结构的文件 (filename.txt
):
>line1
ABC
>line2
DEF
>line3
GHI
>line4
JKL
我想打乱 而非 开头的字符串中的字符 >
。输出将(例如)如下所示:
>line1
BCA
>line2
DFE
>line3
IHG
>line4
KLJ
这就是我尝试打乱字符串中字符的方法:sed 's/./&\n/' | shuf | tr -d "\n"
。看起来它有效,但它没有考虑换行符。此外,它对所有数据执行命令,而不仅仅是不以 >
.
开头的行
这是 GNU awk 中的一个:
$ awk -v seed=$RANDOM ' # get some randomness from shell
function cmp_randomize(i1, v1, i2, v2) { # random for traversal function
return (2 - 4 * rand()) # from 12.2.1 Controlling Array Traversal
} # of Gnu awk docs
BEGIN {
srand(seed) # use the seed, Luke
PROCINFO["sorted_in"]="cmp_randomize" # use above defined function
}
/^[^>]/ { # if starts with anything but >
split([=10=],a,"") # split to hash a
for(i in a) # iterate a in random order
printf "%s", a[i] # output
print "" # newline
next # next record
}1' file # output > starting records
>line1
CAB
>line2
DFE
>line3
GIH
>line4
LKJ
有perl
和ruby
$ # split// to get individual characters
$ # join "" to join characters with empty string
$ # if !/^>/ to apply the change only for lines not starting with >
$ # alternate: perl -MList::Util=shuffle -lne 'print /^>/ ? $_ : shuffle split//'
$ perl -MList::Util=shuffle -lpe '$_=join "", shuffle split// if !/^>/' ip.txt
>line1
CBA
>line2
FED
>line3
IHG
>line4
JKL
$ # $_.chars to get individual characters
$ # * "" to join array elements with empty string
$ ruby -lpe '$_ = $_.chars.shuffle * "" if !/^>/' ip.txt
>line1
BAC
>line2
EDF
>line3
GHI
>line4
JKL
awk
+ coreutils
方法:
awk '/^[^>]/{ system("echo ""| fold -w1 | shuf | tr -d 7\n7"); print ""; next }1' file
示例输出:
>line1
BAC
>line2
EDF
>line3
HGI
>line4
KLJ
对于GNU sed
:
$ cat filename.txt
>line1
ABC
>line2
DEF
>line3
GHI
>line4
JKL
$ sed -r "/^[^>]/s/.*/grep -o . <<< & |sort -R |tr -d '\n'/e" filename.txt
>line1
ABC
>line2
FDE
>line3
HGI
>line4
LKJ
$ sed -r "/^[^>]/s/.*/grep -o . <<< & |shuf |tr -d '\n'/e" filename.txt
>line1
BCA
>line2
FDE
>line3
HIG
>line4
JKL
编辑:sed
在所有 (GNU sed) 4.2.2
上都一样工作,我们可以通过删除 e
修饰符来打印 sed 生成的原始命令字符串:
sed -r '/^[^>]/s/.*/grep -o . <<< & |shuf |tr -d "\n"/' filename.txt
>line1
grep -o . <<< ABC |shuf |tr -d "
"
>line2
grep -o . <<< DEF |shuf |tr -d "
"
>line3
grep -o . <<< GHI |shuf |tr -d "
"
>line4
grep -o . <<< JKL |shuf |tr -d "
"
然后,sed
的s
命令的e
修饰符会调用sh
执行。 CentOS
上的sh
是符号link到bash
,但在Ubuntu上是符号link到dash
, dash
可能不支持 <<<
(here-string
).
# on Ubuntu, enter into sh terminal:
$ grep -o . <<< JKL |shuf |tr -d '\n'
sh: 2: Syntax error: redirection unexpected
$ echo JKL |grep -o . |shuf |tr -d '\n'
KLJ
所以,我需要修改我的答案以同时适用于 bash
和 dash
:
$ sed -r '/^[^>]/s/.*/echo -n & |grep -o . |shuf |tr -d "\n"/e' filename.txt
>line1
ACB
>line2
DFE
>line3
IHG
>line4
LJK
简单说明:
/^[^>]/
: 强制 sed
处理以 (^
) 开头且不是 >
([^>]
) 的行。
s/.*/echo -n & |grep -o . |shuf |tr -d "\n"/
:.*
是整行,用&
代替,所以&
是整行,然后生成一个普通命令字符串 echo -n ORIGIN_LINE |grep -o . |shuf |tr -d "\n"
,可以随机排列一行。
- 最后,使用
s
命令的e
修饰符来执行上面生成的普通命令字符串。
这可能适合您 (GNU sed):
sed '/^>/b;s/./&\n/g;s/.$//;s/.*/echo "&"|shuf/e' file
打印以 >
开头的行,但不处理。否则,在当前行的每个字符之间插入换行符并删除最后一个不需要的换行符。然后 echo
生成文件并通过 shuf
命令(必要时可以替换 sort -R)并打印结果。
N.B。此解决方案在替换命令上使用 GNU 特定的 e
标志,但是结果可以传递给 shell,如下所示:
sed '/^>/s/.*/echo "&"/;t;s/./&\n/g;s/.$//;s/.*/echo "&"|shuf/' file | sh
我有一个具有以下结构的文件 (filename.txt
):
>line1
ABC
>line2
DEF
>line3
GHI
>line4
JKL
我想打乱 而非 开头的字符串中的字符 >
。输出将(例如)如下所示:
>line1
BCA
>line2
DFE
>line3
IHG
>line4
KLJ
这就是我尝试打乱字符串中字符的方法:sed 's/./&\n/' | shuf | tr -d "\n"
。看起来它有效,但它没有考虑换行符。此外,它对所有数据执行命令,而不仅仅是不以 >
.
这是 GNU awk 中的一个:
$ awk -v seed=$RANDOM ' # get some randomness from shell
function cmp_randomize(i1, v1, i2, v2) { # random for traversal function
return (2 - 4 * rand()) # from 12.2.1 Controlling Array Traversal
} # of Gnu awk docs
BEGIN {
srand(seed) # use the seed, Luke
PROCINFO["sorted_in"]="cmp_randomize" # use above defined function
}
/^[^>]/ { # if starts with anything but >
split([=10=],a,"") # split to hash a
for(i in a) # iterate a in random order
printf "%s", a[i] # output
print "" # newline
next # next record
}1' file # output > starting records
>line1
CAB
>line2
DFE
>line3
GIH
>line4
LKJ
有perl
和ruby
$ # split// to get individual characters
$ # join "" to join characters with empty string
$ # if !/^>/ to apply the change only for lines not starting with >
$ # alternate: perl -MList::Util=shuffle -lne 'print /^>/ ? $_ : shuffle split//'
$ perl -MList::Util=shuffle -lpe '$_=join "", shuffle split// if !/^>/' ip.txt
>line1
CBA
>line2
FED
>line3
IHG
>line4
JKL
$ # $_.chars to get individual characters
$ # * "" to join array elements with empty string
$ ruby -lpe '$_ = $_.chars.shuffle * "" if !/^>/' ip.txt
>line1
BAC
>line2
EDF
>line3
GHI
>line4
JKL
awk
+ coreutils
方法:
awk '/^[^>]/{ system("echo ""| fold -w1 | shuf | tr -d 7\n7"); print ""; next }1' file
示例输出:
>line1
BAC
>line2
EDF
>line3
HGI
>line4
KLJ
对于GNU sed
:
$ cat filename.txt
>line1
ABC
>line2
DEF
>line3
GHI
>line4
JKL
$ sed -r "/^[^>]/s/.*/grep -o . <<< & |sort -R |tr -d '\n'/e" filename.txt
>line1
ABC
>line2
FDE
>line3
HGI
>line4
LKJ
$ sed -r "/^[^>]/s/.*/grep -o . <<< & |shuf |tr -d '\n'/e" filename.txt
>line1
BCA
>line2
FDE
>line3
HIG
>line4
JKL
编辑:sed
在所有 (GNU sed) 4.2.2
上都一样工作,我们可以通过删除 e
修饰符来打印 sed 生成的原始命令字符串:
sed -r '/^[^>]/s/.*/grep -o . <<< & |shuf |tr -d "\n"/' filename.txt
>line1
grep -o . <<< ABC |shuf |tr -d "
"
>line2
grep -o . <<< DEF |shuf |tr -d "
"
>line3
grep -o . <<< GHI |shuf |tr -d "
"
>line4
grep -o . <<< JKL |shuf |tr -d "
"
然后,sed
的s
命令的e
修饰符会调用sh
执行。 CentOS
上的sh
是符号link到bash
,但在Ubuntu上是符号link到dash
, dash
可能不支持 <<<
(here-string
).
# on Ubuntu, enter into sh terminal:
$ grep -o . <<< JKL |shuf |tr -d '\n'
sh: 2: Syntax error: redirection unexpected
$ echo JKL |grep -o . |shuf |tr -d '\n'
KLJ
所以,我需要修改我的答案以同时适用于 bash
和 dash
:
$ sed -r '/^[^>]/s/.*/echo -n & |grep -o . |shuf |tr -d "\n"/e' filename.txt
>line1
ACB
>line2
DFE
>line3
IHG
>line4
LJK
简单说明:
/^[^>]/
: 强制sed
处理以 (^
) 开头且不是>
([^>]
) 的行。s/.*/echo -n & |grep -o . |shuf |tr -d "\n"/
:.*
是整行,用&
代替,所以&
是整行,然后生成一个普通命令字符串echo -n ORIGIN_LINE |grep -o . |shuf |tr -d "\n"
,可以随机排列一行。- 最后,使用
s
命令的e
修饰符来执行上面生成的普通命令字符串。
这可能适合您 (GNU sed):
sed '/^>/b;s/./&\n/g;s/.$//;s/.*/echo "&"|shuf/e' file
打印以 >
开头的行,但不处理。否则,在当前行的每个字符之间插入换行符并删除最后一个不需要的换行符。然后 echo
生成文件并通过 shuf
命令(必要时可以替换 sort -R)并打印结果。
N.B。此解决方案在替换命令上使用 GNU 特定的 e
标志,但是结果可以传递给 shell,如下所示:
sed '/^>/s/.*/echo "&"/;t;s/./&\n/g;s/.$//;s/.*/echo "&"|shuf/' file | sh