I have a lot of html files that I want to rename according to the content of the tag h1.

Any suggestion on how to do it on bash?

Example of a file:

<!DOCTYPE html><html lang="pt-BR"><head><meta charset="utf-8"><title>Repositório - MAIS</title>
 <script src="lib/tudo.js"></script>
 <link rel="stylesheet" href="lib/style.css">
<div id="cabecalho"></div>
<div id="corpo">

<div class="Experimento"></div>
<div class="gallery">
<img class="image-gallery" src="img/2dados.png">

<br><br><strong>Mídia:</strong> experimento (uma aula dupla)

<br><br><strong>Descrição:</strong> este experimento propõe 4 jogos diferentes, todos baseados no lançamento de 2 dados comuns. Discutindo as chances de cada jogador vencer cada um dos jogos, os estudantes terão a chance de discutir vários conteúdos relacionados à probabilidade

<br><br><strong>Conteúdo:</strong> experimento aleatório, espaço amostral, eventos equiprováveis, probabilidade

<br><br><strong>Recomendação de uso:</strong> este experimento pode ser usado como introdução ou aplicação dos conceitos iniciais de probabilidade.

<br><br><strong>Autoria:</strong> este experimento foi desenvolvido pela <a class="externo" href="http://www.mais.mat.br" target="_blank">Mais</a> e pode ser utuilziado e distribído livremente, contanto que citada a autoria original.

<a class="download" href="http://www.mais.mat.br/recursos/images/5/5b/2dados.pdf">Baixar</a>

<div id="rodape"></div>

I want the file renamed to "teste.html"

If it is helpful, this tag is always on the 8th line of each file and alone (nothing else on the same line). Also, there is always only one occurrence of h1 in each file.

  • 3
    I suggest to use an XML/HTML parser (xmlstarlet, xmllint ...). – Cyrus Feb 17 '18 at 17:23
  • Please add sample input. – Gilles Quenot Feb 17 '18 at 17:28
  • you should never rely on a line number when dealing with XML/HTML data. Post the crucial tag name and its content – RomanPerekhrest Feb 17 '18 at 17:30
  • Are you suggesting an edit your own post? Don't worry, the system is smart and the mods can merge your accounts. (Btw, using multiple accounts is allowed here, only misusing this is not (for example, upvoting your own post on your other account)). – peterh - Reinstate Monica Feb 17 '18 at 19:51
  • @peterh I'm afraid mods can't merge accounts. Leo, please request a merge of your two accounts by following the instructions here: unix.stackexchange.com/help/merging-accounts – terdon Feb 18 '18 at 12:31

With :


<!DOCTYPE html>


for file in *.html; do
    tag=$(xmllint --xpath '//b/text()' $file)
    echo mv "$file" "${tag}_$file"


Put off the echo command when your tests become ok to run the command for real

|improve this answer|||||
  • 1
    maybe echo mv "$file" "${tag}_$file" - that way the quotes are still correct if echo is deleted from the line. Also, why not put in a <h1>...</h1> example since that's what the OP wanted? finally, a pipe to head -n 1 would be useful in case there's more than one h1 tag. – cas Feb 18 '18 at 10:39

The right way with find + xmlstarlet tools:

find . -type f -name "*.html" -exec sh -c \
'name=$(xmlstarlet sel -t -v "//tagname" $1 2>/dev/null); 
 [ ! -z "$name" ] && echo mv "$1" "${1%%/*}/${name}.html"' _ {} \;
  • name - variable which is assigned with a value (the contents of the tag tagname) for the new filename
  • [ ! -z "$name" ] - check if a new filename is not empty (i.e. <tagname> was found and it had a value)
|improve this answer|||||

With xmlstarlet:

xmlstarlet format --html teste.html | xmlstarlet select --html --template --value-of '//html/body/div/h1'



I used xmlstarlet format --html teste.html to fix your non valid html code.

|improve this answer|||||

If tag is alone on the 8-th line, you have many way to pick it.

tag=$( awk NR==8 file )

tag=$( awk 'NR == 8 { print ;}' file )


  • NR is number of record (line number)
  • print is implied action


tag=$(sed -n 8p file)


  • -n will not echo line
  • 8p print 8th line.

and many other.

as notted in comment, relaying on line number is risky. If file is a valid xml file, extracting tag would be easier and safest.

|improve this answer|||||

My final solution was the code below, combining two suggestions. Thank you, guys!

for file in *.html; do
    tag=$(xmlstarlet format --html $file | xmlstarlet select --html --template --value-of '//html/body/div/h1')
    mv "$file" "${tag}.html"

It worked great for my files!

|improve this answer|||||

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.