BASH-перемешивание символов в строках из файла



У меня есть файл (filename.txt) со следующей структурой:



>line1
ABC
>line2
DEF
>line3
GHI
>line4
JKL


Я хотел бы перетасовать символы в строках, которые делают не start wit >. Выходные данные (например) будут выглядеть следующим образом:



>line1
BCA
>line2
DFE
>line3
IHG
>line4
KLJ


Это то, что я пытался перетасовать символы в строке: sed 's/./&n/' | shuf | tr -d "n". Похоже, что это работает, но не учитывает новые строки. Более того, он выполняет команду на всех данных, а не только на строках, которые не начинаются с >.

753   5  

5 ответов:

С 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 "$1"| fold -w1 | shuf | tr -d \047\n\047"); 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

Edit: sed работает все так же на всех (GNU sed) 4.2.2, мы можем распечатать сырую командную строку, сгенерированную sed, удалив модификатор e:

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 "
"

Тогда модификатор e команды s sed вызовет sh для ее выполнения. sh на CentOS является символической ссылкой на bash, но на Ubuntu это символическая ссылка на 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

Простые объяснения:

  1. /^[^>]/: заставить sed иметь дело с линиями, которые начинаются (^) не с a > ([^>]).
  2. s/.*/echo -n & |grep -o . |shuf |tr -d "\n"/: .* это вся строка, используйте &, чтобы держать ее в замене, так что & - это вся исходная строка, а затем создайте простую командную строку echo -n ORIGIN_LINE |grep -o . |shuf |tr -d "\n", которая может перетасовать строку.
  3. Наконец, используйте модификатор e команды s для выполнения простой командной строки, сгенерированной выше.

Вот один в 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($0,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

Это может сработать для вас (GNU sed):

sed '/^>/b;s/./&\n/g;s/.$//;s/.*/echo "&"|shuf/e' file

Выводите строки, начинающиеся с >, но не обрабатывайте их. В противном случае вставьте новые строки между каждым символом в текущей строке и удалите последнюю нежелательную новую строку. Затем echo созданный файл и передать его через команду shuf (sort-R может быть заменен при необходимости) и распечатать результат.

N. B. Это решение использует флаг GNU specific e в команде подстановки, однако результат может быть передан в оболочку, например Итак:

sed '/^>/s/.*/echo "&"/;t;s/./&\n/g;s/.$//;s/.*/echo "&"|shuf/' file | sh

Comments

    Ничего не найдено.