How can I rename all files within a folder with the first word of their content? For example if a.txt contains “Unix is an OS” in its first line then a.txt should be renamed to Unix.txt

  • Please correct title into something like "How do I rename multiple file in unix?" – Johan May 14 '11 at 9:55
  • Missed that on this site, I thought I did not have enought rep here... – Johan May 14 '11 at 11:11
  • That title is also too misleading. It leaves out the core detail that the new name must be based on file content. – jmtd May 20 '11 at 12:41

Try this:

for f in *.txt; do d="$(head -1 "$f" | awk '{print $1}').txt"; if [ ! -f "$d" ]; then mv "$f" "$d"; else echo "File '$d' already exists! Skiped '$f'"; fi; done

or more long variant (as script):

for f in *.txt; do
    d="$(head -1 "$f" | awk '{print $1}').txt"
    if [ ! -f "$d" ]; then
        mv "$f" "$d"
        echo "File '$d' already exists! Skiped '$f'"

In case when destination file exists this one-liner skips it.

  • 5
    I'd simplify head -1 "$f" | awk '{print $1}' to <"$f" awk {print $1; exit}. – Gilles 'SO- stop being evil' May 14 '11 at 11:09
  • This doesn't work if the first line has spaces in it... – Guillochon Nov 8 '17 at 16:22

Here is my approach.

for file in *; 
    if [[ -f $file ]]; 
        # cut word by single white space
        fileword=$(head -n1 "$file" | cut -f1 -d" ");
        # Everything after first dot is considered as extention
        ext=$(echo $file | sed 's/.*\.\(.*\)/.\1/g')
        [ "$file" != "$fileword" ] && $(mv  "$file"  "$fileword$ext")

Use this oneliner

for i in *; do if [ ! -f $i ]; then echo "skipping $i"; else newname=`head -1 $i | sed 's/^\s*\([a-zA-Z0-9]\+\).*$/\1/'`; [ -n "$newname" ] && mv -i $i $newname.txt || echo "error at: $i"; fi; done

This will replace all files with the first word in that file + .txt. I defined first word to be the first occurrence of [a-zA-Z0-9]+, discarding leading white spaces.
Disclaimer: Please just use it if you are sure that there is a first word on line one in each file! Otherwise you might experience unexpected results ;-)

for i in *.txt
d="$(head -1 "$i" | cut -d " " -f1).txt";
mv "$i" "$d"
  • The character after the first word could be different than space (a comma for example) – Philippe Blayo Nov 19 '12 at 18:40
for i in *.txt; do mv "$i" "$(head -1 "$i")".txt; done

On your own risk: :)

find -exec echo -n mv {} " " ";" -exec sed '1s/ .*//;q' {} ";" > tmp.sh && bash tmp.sh

This works with easy filenames, containing easy words. A file "O'Reilly" containing as first word "Eto'o" will fail. Miserably.

  • You're missing a step of quoting. What if there's a file called some'thing, or if the first word is D'oh? – Gilles 'SO- stop being evil' Jun 14 '11 at 9:18
  • Yes, I see. How would you do it? Not at all - choose a different approach? – user unknown Jun 14 '11 at 20:00
  • It's technically possible to generate a shell script, but it's calling for trouble. You “just” need to get the quoting right. There's no call for it here, just extract the first word and call mv right there, like the other answers. You can keep your sed command, it's a fine way to extract the first word. – Gilles 'SO- stop being evil' Jun 15 '11 at 8:04
  • In praxis, I would, if I used this approach, use two commands - ... > tmp.sh, and review tmp.sh manually. Then invoke bash tmp.sh. With a lot of funky filenames, I wouldn't do it at all. But one or two manual corrections would be fine in 100 files. In about 1000 files, a manual review would start becoming work. – user unknown Jun 15 '11 at 17:14

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.