Existem maneiras melhores de classificar do que fazê-lo apenas no bash. Esta não é uma boa resposta à sua pergunta - não é simples (porque usa vários recursos do bash que não são comuns), e não faz as coisas "The Unix Way", que é usar ferramentas que são pré-construídos para fazer uma coisa e fazer isso bem (como ordenar).
Eu decidi escrever esta resposta para ajudar a destacar que o shell padrão da sua conta foi criado para executar comandos e redirecionar E / S. Só porque um shell tem uma grande quantidade de recursos, como o Bash não significa que é o melhor ferramenta para um trabalho específico. Muitas vezes você verá respostas que sugerem o uso de awk ou perl (ou jq ou sort ...) em vez de tentar cortá-lo em uma concha apenas script .
Dito isto, o bash pode ordenar - não é apenas interno. Vou me repetir: ainda não é uma boa ideia. Mas você consegue fazer isso. Abaixo estão quatro funções, implementadas no bash, que ordena duas maneiras diferentes em cada um dos dois campos.
As funções usam:
- arrays
- variáveis de função local
- mapfile
-
for ((
loops - complexo substituição de parâmetros
- operador
[[
test de bash para fazer o classificação real - operador
[[
test de bash para analisar os dois valores - bash
read
integrado
A classificação de inserção não é eficiente ( O (n) 2 ), mas certamente razoável para conjuntos de dados pequenos, como o exemplo de 11 linhas. As quatro funções foram executadas em segundos para os dados de amostra, mas para um arquivo de entrada de 1.000 linhas geradas aleatoriamente, as ordenações de "matriz separada" levaram ~ 15 segundos enquanto as versões "no local" levaram ~ 60 segundos por causa de todas do reprocessamento dos valores. Compare isso com o utilitário de classificação padrão que classificou o arquivo de 1.000 linhas em cada coluna em sub-milésimos -uma segunda vez.
As duas funções "inplace" tentam economizar alguns bytes criando apenas uma matriz (e algumas variáveis únicas para valores de loop e troca); no lado positivo, ele usa uma função bash para mapear o conteúdo do arquivo em matrizes. As funções "chaveadas" são cautelosas e criam duas matrizes separadas, uma para ordenar as chaves desejadas e outra para os valores reais.
function sort_inplace_f1 {
local array
mapfile -t array < "$1"
local i j tmp
for ((i=0; i <= ${#array[@]} - 2; i++))
do
for ((j=i + 1; j <= ${#array[@]} - 1; j++))
do
local ivalue jvalue
[[ ${array[i]} =~ ([^[:space:]]+)[[:space:]]+(.*) ]]
ivalue="${BASH_REMATCH[1]}"
[[ ${array[j]} =~ ([^[:space:]]+)[[:space:]]+(.*) ]]
jvalue=${BASH_REMATCH[1]}
if [[ $ivalue > $jvalue ]]
then
tmp=${array[i]}
array[i]=${array[j]}
array[j]=$tmp
fi
done
done
printf "%s\n" "${array[@]}"
}
function sort_inplace_f2 {
local array
mapfile -t array < "$1"
local i j tmp
for ((i=0; i <= ${#array[@]} - 2; i++))
do
for ((j=i + 1; j <= ${#array[@]} - 1; j++))
do
local ivalue jvalue
[[ ${array[i]} =~ ([^[:space:]]+)[[:space:]]+(.*) ]]
ivalue="${BASH_REMATCH[2]}"
[[ ${array[j]} =~ ([^[:space:]]+)[[:space:]]+(.*) ]]
jvalue=${BASH_REMATCH[2]}
if [[ $ivalue > $jvalue ]]
then
tmp=${array[i]}
array[i]=${array[j]}
array[j]=$tmp
fi
done
done
printf "%s\n" "${array[@]}"
}
function sort_keyed_f1 {
local c1 c2 keys values
while IFS=' ' read -r c1 c2
do
keys+=("$c1")
values+=("$c1 $c2")
done < "$1"
local i j tmpk tmpv
for ((i=0; i <= ${#keys[@]} - 2; i++))
do
for ((j=i + 1; j <= ${#keys[@]} - 1; j++))
do
if [[ ${keys[i]} > ${keys[j]} ]]
then
# swap keys
tmpk=${keys[i]}
keys[i]=${keys[j]}
keys[j]=$tmpk
# swap values
tmpv=${values[i]}
values[i]=${values[j]}
values[j]=$tmpv
fi
done
done
printf "%s\n" "${values[@]}"
}
function sort_keyed_f2 {
local c1 c2 keys values
while IFS=' ' read -r c1 c2
do
keys+=("$c2")
values+=("$c1 $c2")
done < "$1"
local i j tmpk tmpv
for ((i=0; i <= ${#keys[@]} - 2; i++))
do
for ((j=i + 1; j <= ${#keys[@]} - 1; j++))
do
if [[ ${keys[i]} -gt ${keys[j]} ]]
then
# swap keys
tmpk=${keys[i]}
keys[i]=${keys[j]}
keys[j]=$tmpk
# swap values
tmpv=${values[i]}
values[i]=${values[j]}
values[j]=$tmpv
fi
done
done
printf "%s\n" "${values[@]}"
}
Mesmo depois de tudo isso, você ainda precisa de uma das principais "funções" do seu shell, ou seja, redirecionar a saída para um arquivo:
sort_keyed_f1 input-file > alpha_sorted.txt
sort_keyed_f2 input-file > numbers_sorted.txt