How to Deal With Spaces in Filenames on Linux

Configurare noua (How To)

Situatie

If you have a filename with spaces on a Linux system, wrapping your filename in quote marks lets Bash treat it correctly. Tab completion makes entering filenames on the command line easy, even if they contain spaces.

Like most operating systems, Linux supports filenames with spaces in them. But using these filenames on the command line isn’t always straightforward. Here are several ways you can handle filenames containing spaces.

Solutie

The Humble Filename

Everything stored on your computer’s hard drive needs to have a name. Without a name, no files would exist. All of the applications and daemons that are launched when your computer boots up, and all of the software that you use, has to be identified and stored in a file system. That identification is the name of the file.’

The same thing applies to the files that you create or install. All your documents, images, and music need filenames. Without filenames, none of your digital assets could exist. Because filenames are so important, Linux tries hard to impose as few rules about their composition as it can.

On Linux, a filename may contain any character apart from the forward slash “/” and the null character, 0x00. The null character is used to mark the end of a string, so it can’t be present in the string itself, or Linux would truncate the filename at the position of the null character. The “/” forward slash is used as the separator in directory paths.

Filenames are case-sensitive, and can be up to 255 bytes long, including the null character. Directory paths can be up to 4096 bytes long, including the null character. Note that this is their length in bytes, which might not equate directly to characters. 16-bit Unicode characters, for example, take two bytes each.

Retro-computing enthusiasts and those with long memories will know that in the early days of personal computers, Microsoft’s Disk Operating System, DOS, was case-insensitive and had a filename limit of eight characters, plus a three-character extension.

You had to be very thoughtful and sometimes creative when you named files. By comparison, the freedom we have today means we can name files whatever we want, with little thought to anything other than the description we’re creating for that file. But with filenames, what trips us up most often isn’t the characters we type, it’s the spaces between them.

Why Spaces in Linux File Names Are a Pain

Shells such as Bash will interpret a space-separated string of words as individual command arguments, not a single argument. Here’s an example, using touch to create a new file called “my new file.txt.”

touch my new file.txt
ls

Trying to use touch to create a file with spaces in its name

As we can see, ls shows us that there are three files created, one called “my”, another called “new”, and one more called “file.txt.”

Note that touch didn’t complain or throw an error. It carries out what it thinks we’re asking it to do. So it silently returns us to the command line. If we’re not motivated to check, we won’t know things haven’t gone according to plan.

To create the file we wanted, we’ve got to quote or escape.

How to Quote and Escape Spaces

If we quote the entire filename, touch knows it needs to treat the quoted text as a single argument.

touch 'my new file.txt'
ls

Using touch to create file with spaces in its name, with the whole filename enclosed in quotes

This time we get the single file that we expect.

We can get the same result if we use the backslash character “\” to escape the spaces. By “escaping” the spaces they’re not treated as special characters—that is, argument separators—they’re considered to be plain old spaces.

touch my\ second\ new\ file.txt
ls

Using touch to a create a file with spaces in its name escaped with backslashes

That works, but escaping spaces makes typing filenames slower and error-prone. Things can get really ugly if you have directory names with spaces in them too.

cp dir one/my\ text\ file.txt dir\ two/my\ text file.bak
ls

Using escaped spaces in a command to copy a file from one directory to another

That command copies a single text file from a directory called “dir one” to a directory called “dir two”, and saves the copy as a BAK file. And it’s a fairly simple example.

How to Fix the Space Problem at Its Source

If they’re your own files, you could take the policy decision to never use spaces, and create (or bulk rename) filenames like this.

mynewtextfile.txt

Admittedly, that’s a robust solution but it’s still ugly. There are better options, such as using dashes “-” or underscores “_” to separate your words.

my-new-text-file.txt
my_new_text_file.txt

Both of these will sidestep the problem, and they’re readable. If you don’t want to add extra characters to your filenames, you can use CamelCase to make your filenames readable, like this:

MyNewTextFile.txt
Tab Expansion Makes Dealing With Spaces Easy

Of course, adopting a naming convention and sticking to it will only help when you’re dealing with your own files. Files that come from anywhere else are unlikely to follow your adopted naming convention.

  • You can use tab expansion to help you accurately “fill out” filenames for us. Lets say we want to delete the BAK file we created in “dir two”, using rm.
  • We start by typing “rm dir” because we’re using the rm command and we know the directory name starts with “dir.”
rm dir

Typing the start of a command, before pressing tab to use tab completion

Pressing the “Tab” key causes Bash to scan for matches in the current directory.

Pressing tab has added a backslash and a space to the partial directory path

There are two directories that start with “dir”, and in both cases the next character is a space. So Bash adds the backslash character “\” and a space. Bash then waits for us to provide the next character. It needs the next character to differentiate between the two possible matches in this directory.

We’ll type a “t”, for “two”, and then press “Tab” once more.

The directory path after typing "t" and pressing tab

Bash completes the directory name for us and waits for us to type the start of the filename.

We only have one file in this directory, so typing the first letter of the filename, “m”, is enough to let Bash know which file we want to use. Typing “m” and pressing “Tab” completes the filename for us, and “Enter” executes the entire command.

The entire filename completed by pressing "m" and pressing Tab.

Tab expansion makes it easy to ensure you get filenames right, and it also speeds up navigating and typing on the command line in general.

How to Use Filenames With Spaces in Bash Scripts

It’s no surprise that scripts have exactly the same issues with spaces in filenames as the command line does. If you are passing a filename as a variable make sure you quote the variable name.

This little script checks the current directory for files that match the file pattern “*.txt”, and stores them in a variable called file_list. A for loop is used to perform a simple action on each one.

#!/bin/bash

file_list=*.txt

for file in $file_list
do
  ls -hl $file
done

Copy this text into an editor and save it to a file called “files.sh.” Then use the chmod command to make it executable.

chmod +x files.sh

Using chmod to make the script executable

We’ve got some files in this directory. One has a simple file name, and the other two use underscores “_” or dashes “-” instead of spaces. This is what we see when we run the script.

./files.sh

Running the files.sh script with filenames containing no spaces

That seems to work nicely. But let’s change the files in the directory for files that contain spaces in their names.

./files.sh

Running the files.sh script with filenames containing spaces

Every word in each filename is handled as though it was a filename on its own, and so the script fails. But all we need to do to make the script handle spaces in filenames is to quote the $file variable inside the for loop.

#!/bin/bash

file_list=*.txt

for file in $file_list
do
ls -hl "$file"
done

Note that the dollar sign “$” is inside the quotes. We made that change and saved it to the “files.sh” script file. This time, the filenames are handled correctly.

./files.sh

The modified files.sh script correctly handling files with spaces in their filenames

Tip solutie

Permanent

Voteaza

(5 din 9 persoane apreciaza acest articol)

Despre Autor

Leave A Comment?