Suponha que eu tenha um arquivo tão estruturado
/home/zz/AUTHORBOOKS/Author-Chomsky-Who-Rules-the-World.epub
/home/zz/AUTHORBOOKS/Author-Cioran-Il-nulla.epub
/home/zz/BOOKS/Author-Artemis-Mathematica-Examples.nb
/home/zz/Books/Author-Zigniwe-Hisory-Medicine.pdf
/home/z1/OLDBOOKS1/OLDBOOKS2/Author-Watanabe-Waterloo.pdf
/home/z2/OLDBOOKS1/OLDBOOKS2/Author-Barbero-Lepanto.epub.pdf
Eu gostaria de um arquivo classificado desta forma:
/home/zz/BOOKS/Author-Artemis-Mathematica-Examples.nb
/home/z2/OLDBOOKS1/OLDBOOKS2/Author-Barbero-Lepanto.epub.pdf
/home/zz/AUTHORBOOKS/Author-Chomsky-Who-Rules-the-World.epub
/home/zz/AUTHORBOOKS/Author-Cioran-Il-nulla.epub
/home/z1/OLDBOOKS1/OLDBOOKS2/Author-Watanabe-Waterloo.pdf
/home/zz/Books/Author-Zigniwe-History-Medicine.pdf
Ou seja, em ordem alfabética, de acordo com a stringAuthor-...
Como você pode ver, a posição de Author-...
não é constante.
Como posso fazer isso?
Responder1
Experimente o seguinte bash
comando:
sort -t- -d -k2 -o output.txt input.txt
Possui quatro opções mais o nome do arquivo de entrada input.txt
. Se este arquivo não estiver no diretório atual, você terá que fornecer o arquivo path/to/the/folder/input.txt
. As opções e seus argumentos são os seguintes:
- -t marca o separador de campos. Usamos
-
como separador, para que tudo antes e depois de-
sejam considerados colunas separadas. - -d indica classificação de dicionário. Por exemplo, a Apple está antes de Berry.
- -k2 indica a coluna pela qual classificar, neste caso a segunda coluna. Observe que a primeira coluna é tudo antes da primeira
-
. Por exemplo,/home/zz/BOOKS/Author
. A segunda coluna está entre a primeira e a segunda-
, ou sejaArtemis
,. - -o
output.txt
redireciona a saída classificada para um arquivo em vez de para o terminal.
Espero que isto ajude
Responder2
Embora seja um exagero para o presente exemplo por causa dosolução proposta na resposta do usuário68186, você poderia fazer algo mais geralmente assim no GNU awk:
gawk -F/ '
function mycmp(i1,v1,i2,v2) {
m = split(v1,a);
n = split(v2,b);
return a[m]"" > b[n]"" ? 1 : a[m]"" < b[n]"" ? -1 : 0
}
{
lines[NR] = $0
}
END {
PROCINFO["sorted_in"] = "mycmp";
for(i in lines) print lines[i]
}
' file
Observe que ele classifica de acordo com o valor lexical de tudo depois do último /
- então se o formato for Author-<author name>-<title>.<extension>
esse será
- a string fixa
Author-
(que não tem efeito, pois tem o mesmo peso para todas as linhas); então <author name>-
; então<title>.
; então<extension>
Isto é semelhante ao modo como o sort
KEYDEF simples do GNU -t- -k2
funciona, ou seja, a chave de classificação efetiva começa no final da <author name>
linha e continua até o final da linha.
Um delimitador explícito é omitido das split
chamadas para que elas herdem o valor de FS
, facilitando a alteração para sistemas que usam um separador de caminho diferente. As strings vazias anexadas ""
na mycmp
função forçam a comparação lexical mesmo se os nomes dos arquivos forem numéricos - veja por exemploComo o awk converte entre strings e números
Se preferir seguir o sort
comando, você pode aproveitar o GNU awkComunicações bidirecionais com outro processopara:
- duplique o último
/
campo separado no início da string - passe o resultado para um
sort
comando - leia novamente o resultado classificado, remova o prefixo duplicado e imprima
ou seja
gawk -F/ '
BEGIN {OFS=FS; cmd = "sort -d"}
{print $NF $0 |& cmd}
END {
close(cmd,"to");
while(cmd |& getline){$1 = ""; print};
close(cmd,"from")
}
' file
Há um truque aqui, pois os caminhos absolutos (as linhas começam com /
) implicam um campo inicial vazio; para lidar com caminhos relativos que você precisa alterar print $NF $0
para print $NF,$0
inserir o separador "ausente" e, talvez, usar um regex sub()
em vez do mais simples $1 = ""
para remover o elemento inicial.
Além de ser potencialmente mais rápido/mais eficiente em termos de memória do que a gawk
solução pura, isso permite que outras sort
opções sejam adicionadas diretamente, por exemplo. cmd = "sort -d -t " FS " -k1,1r"
.