I need to rename a few thousand text files to be the first word in the text file plus the file extension (.txt) using the terminal. All the files are in a single directory, and are currently named int the pattern "xx0001.txt' through 'xx9999.txt'.

The first word in each file is of this pattern: '##221251', so maybe my issue comes from needing to comment out the pound signs.

I've tried:

rename File.ReadAllText('*.txt').split(' ')[0]

Which throws the error:

zsh: no matches found: File.ReadAllText(*.txt).split( )[0]

Thanks in advance for your help. I'm a true novice.

2 Answers 2


Assuming that words are SPC, TAB or NUL separated and the first word is on the first line, try:

for file (*.txt) {
  read -r word rest < $file && mv -i -- $file $word.txt

To split on SPC only, replace read with IFS=' ' read.

I don't know what language that rename File.ReadAllText('*.txt').split(' ')[0] code is meant to be written in, but that's certainly not zsh syntax (nor that of any other shell I know).

A more direct zsh translation of what I suppose that code is meant to do would be:

for file (*.txt) mv -i -- $file ${$(<$file)[1]}

Though that reads and splits the whole file in memory and doesn't do much error checking. That one splits on SPC, TAB, NUL or NL and is not restricted to the first being on the first line.

To make it quicker, you can run zmodload zsh/files beforehand which would replace the mv command with a builtin version (saving the costly fork and exec upon invocation).

rename itself is the name of an example program that has been shipped with perl since at least the 80s. The argument is perl code used to compute the replacement name. Not all systems ship with that rename command and on some systems the rename command is something completely different. If your rename is the perl one though, you could do:

rename '
  if (open FILE, "<", $_ and my $line = <FILE>) {
    chomp $line;
    my @words = split " ", $line;
    $_ = "$words[0].txt" if @words;
  }' ./*.txt

Here using single quotes, so that what's inside them is passed verbatim to perl as perl language code.

You may also want to change *.txt to *.txt(.) or *.txt(-.) to only consider regular file (skipping directories, fifos, devices and other non-regular types of files).

  • looks like MS .NET stuff...
    – Fubar
    Commented Apr 24, 2020 at 17:57
  • "I don't know what language that rename File.ReadAllText('*.txt').split(' ')[0] code is meant to be written in" could be python. Some regard python as their shell...
    – der bender
    Commented Apr 24, 2020 at 19:35
  • Thank you for the detailed explanation. Your initial answer essentially did what I needed, but I removed the -i because I didn't want to manually enter y/n for each file.
    – mqh5962
    Commented Apr 28, 2020 at 17:30
  • @mqh5962, the -i doesn't prompt for each file, only when mv is about to overwrite an existing file. Commented Apr 28, 2020 at 17:55

In vim I would do the following (even though it is dirty as hell):

:$!ls *.txt that gives you a list of all .txt files in your directory

:%norm A `sed 1q < | cut -f1 -d' '`

That appends a template for a command that gets the first word in a file (or the first thing that is followed by a space rather [usually that is considered the same thing]) which will be completed shortly...

:%norm 0vf yf<p to get the file name from our list which we generated previously and paste it after the <

:%norm Imv˽ to add the move command and a space in the beginning of every line.

:w command.shto save it as a script that can be put through chmod +x command.sh and be run with ./command.sh


There is no sanitation done. That is there is no checking that the first word in the file is a unique name. This maybe given by your application but in the general case it is not. Therefor it maybe that renaming a file to its first word of content results in files overwriting each other. For that reason it is not advisable to do it.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .