Eu tenho um arquivo de texto com strings delimitadas por nova linha. Meu problema é processar cada linha da seguinte forma: embaralhar a ordem dos tokens usando o espaço como delimitador.
Por exemplo:
Entrada:
A B C
Resultado:
C A B
Executar o comando/script repetidamente deve, obviamente, fornecer uma ordem diferente.
Minha solução atual (para uma única linha de texto):
$ cat <file> | tr " " "\n" | shuf | tr "\n" " "
Existe uma combinação de linha de comando legal (melhor) para processar um arquivo de texto com várias linhas?
POSIXly, você poderia fazê-lo com
awk
relativa eficiência (certamente mais eficiente do que executar pelo menos umshuf
utilitário GNU para cada linha da entrada) como:(observe que na maioria das
awk
implementações, executar o mesmo comando duas vezes no mesmo segundo provavelmente fornecerá o mesmo resultado que a semente aleatória padrão usadasrand()
geralmente com base no tempo de época atual em segundos).Seu comando original pode ser simplificado para
shuf -e A B C | tr "\n" " " && echo ""
ou
shuffled=( $(shuf -e A B C) ) ; echo ${shuffled[*]}
O que eu acho um pouco menos hacky e também é mais rápido dos meus testes rudimentares.
Se você tiver um arquivo no
~/test
qual contémVocê pode embaralhar e ecoar cada linha com o seguinte comando
while IFS= read -r line; do shuffled=( $(shuf -e $line) ) ; echo ${shuffled[*]} ; done < ~/test
ou em forma de script:
Onde você pode querer substituir
~/test
para$1
passar argumentos para o script.resultado:
Como isso funciona:
shuf -e
divide em espaços assim como em novas linhas... mas apenas porque tratará ABC como três argumentos.então
shuf -e A B C
irá embaralhar AB e C, masshuf -e "A B C"
não irá embaralhar AB e CPodemos usar isso para ler cada linha em uma matriz e depois imprimi-la novamente com
echo
.while IFS= read -r line;
Lê em cada linha
$line
quando é passado<
para este loop.do shuffled=( $(shuf -e $line) )
Faz uma matriz de cada linha na
$shuffled
variável, literalmente expandindoshuf -e $line
parashuf -e A B C
.echo ${shuffled[*]}
ecoa nossa matriz, por padrão, imprimindo cada elemento com espaços entre eles
< ~/test
alimenta as linhas do
~/test
nosso loop.Dado
em seguida, usando
shuffle
do módulo List::Util do perl:Com bash
read -a
eshuf
(mas muito ineficiente, pois executa 3 utilitários por linha, 2 dos quais não embutidos):Para passar os parâmetros como uma linha:
shuf -e one two three four
é o que você precisa.shuf -e $(cat <file>) | tr "\n" " "
para um arquivo com uma linha, como no seu exemplo.Para várias linhas:
while read line; do shuf -e $line | tr "\n" " " && echo \n; done < <file>
Enquanto como @steeldriver, eu usaria uma ferramenta de processamento de texto adequada
perl
para fazer o trabalho , vou mencionar uma maneira hacky com ozsh
shell:É um pouco de hack. Acabamos usando a geração de nome de arquivo para poder usar o
o
qualificador glob que nos permite implementar ordens de classificação arbitrárias.Aqui, estamos globbing
/
(que sabemos que sempre existe), usamos ume
qualificador glob para substituí-lo pelo conteúdo de nossa matriz e, em seguida, fazemos uman
ordemo
numérica com base naREPLY=$RANDOM
e
expressão.Aqui está uma maneira de fazer isso usando o c-shell "muito difamado":
Aqui está um mais simples. Coloque sua string em uma matriz e use
shuf
para embaralhar