5

When I list files that have spaces in their names, most of the time I see them surrounded by apostrophes :

'famille, vacances, loisirs'

I had to edit a file whose name had to be : Chapitre 2 : L'accès au système.md, with an apostrophe inside of it.


I tried :

gvim 'Chapitre 2 : L''accès au système.md'

doubling the apostrophe in the middle. But it created the file 'Chapitre 2 : Laccès au système.md' instead, with no apostrophe at all.


I tried :

gvim "Chapitre 2 : L'accès au système.md"

and it created a file named : "Chapitre 2 : L'accès au système.md"


I have two questions :

  1. Is (for the system) the file name : "Chapitre 2 : L'accès au système.md" the same than a file named 'Chapitre 2 : L'accès au système.md' if I had succeded in doing so ?

  2. how should I write the file name in my gvim command to get the exact file name 'Chapitre 2 : L'accès au système.md' I would like to read in the outpout of a ls command ?

3 Answers3

7

You're using some system where ls outputs filenames with the shell's quoting rules, to make the output unambiguous. Possibly e.g. GNU ls with QUOTING_STYLE set to shell, or ls from coreutils >= 8.25 where that is the default. The quoting rules of the shell are also important when entering the filenames on the command line.

gvim 'Chapitre 2 : L''accès au système.md' created the file 'Chapitre 2 : Laccès au système.md' instead, with no apostrophe at all.

You gave the shell two back-to-back single-quoted strings, which just get concatenated. In SQL, you can get a literal single quote that way, but in the most common shells you can't(†). The outer single quotes you show shouldn't be part of the file name, they're just what ls shows to make the output unambiguous. The actual filename is Chapitre 2 : Laccès au système.md.

(† POSIX-style shells (like Bash, ksh, and zsh with default settings), (t)csh, and fish take that as concatenation, which is how it works in e.g. Python too. Some other shells (rc/es/akanga) do what SQL does, though, and zsh has the rcquotes option for that.)

gvim "Chapitre 2 : L'accès au système.md" created a file named : "Chapitre 2 : L'accès au système.md"

It most likely created a file called Chapitre 2 : L'accès au système.md. The double quotes aren't part of the name, they're just printed by ls to make the output unambiguous. It used double quotes instead of single quotes here, since the name had a single quote but nothing that would be special in double quotes, so that format was the cleanest. Though


  1. Is (for the system) the file name : "Chapitre 2 : L'accès au système.md" the same than a file named 'Chapitre 2 : L'accès au système.md' if I had succeded in doing so?

If those were the full filenames -- and they're valid as filenames! -- then no, they're not equivalent, since the other contains two double quotes and one single quote, and the other contains three single quotes.

If you mean if they're the same when interpreted using the quoting rules of the shell, then no, again. "Chapitre 2 : L'accès au système.md" represents the string Chapitre 2 : L'accès au système.md, as a single shell word (since the quotes keep it together).

On the other hand, 'Chapitre 2 : L'accès au système.md' represents the strings Chapitre 2 : Laccès, au, système.md (three distinct shell words since there are unquoted spaces) and an open quote with no closing partner. If you entered that on the shell command line, it would wait for input from another line in hope of getting the closing quote. If you entered those as arguments to a command on the shell command line without the final stray quote, that command would probably try to access those three distinct files.

  1. how should I write the file name in my gvim command to get the exact file name 'Chapitre 2 : L'accès au système.md' I would like to read in the outpout of a ls command ?

You can't get ls to output 'Chapitre 2 : L'accès au système.md' in the mode where it outputs shell-style quoted strings, since that's not a valid shell-style quoted string: it has an unclosed quote in the end.


Now, if we go back to what you said first:

I had to edit a file whose name had to be : Chapitre 2 : L'accès au système.md, with an apostrophe inside of it.

There's a few ways to represent that in the shell. One of them is using double quotes, which ls also did for you: "Chapitre 2 : L'accès au système.md". This works because none of the characters inside are special in double quotes (it only has spaces and the single quote to protect), but wouldn't work if the filename contained e.g. a dollar sign. If it did have dollar signs, you could escape them with a backslash: \$.

Another way is to use single quotes for everything but the single quote itself, and to put an escaped single quote where we want one: 'Chapitre 2 : L'\''accès au système.md'. That has three parts: 'Chapitre 2 : L', \', and 'accès au système.md', the quotes and backslash get removed, and the result is concatenated to the single word Chapitre 2 : L'accès au système.md.

ilkkachu
  • 138,973
  • I recommend find -maxdepth 1 to view the filenames in this case. ls, on the other hand, loves to add bells and whistles to the output. – Quasímodo Jul 25 '20 at 12:38
  • @Quasímodo, it depends... getting an unambiguous output can be useful too. If you encounter a filename with a trailing space, the quotes surrounding it start to look very useful. In any case, ls --quoting-style=literal or export QUOTING_STYLE=literal works in GNU ls to get the old behaviour without quoting the output. It's not entirely literal, though, GNU ls replaces e.g. newlines with ? when printing to a terminal. – ilkkachu Jul 25 '20 at 13:12
  • (1) Obviously (?), ls --quoting-style=shell would give the output that the OP is seeing, and ls could be aliased to that. If so, and the shell style isn’t also set as the hard-coded default in ls (ugh) or set by the environment variable, the user can probably get literal filename output by saying \ls to suppress the alias.  … (Cont’d) – G-Man Says 'Reinstate Monica' Jul 26 '20 at 03:11
  • (Cont’d) …  (2) You can use ls -b, --quoting-style=c or --quoting-style=escape to see control characters in C style (e.g., \r or \016), or --show-control-chars to get them literally (i.e., raw). (--quoting-style=c will also enclose the entire name in " quotes, and escape any quotes in the name.) – G-Man Says 'Reinstate Monica' Jul 26 '20 at 03:11
  • @G-ManSays'ReinstateMonica', it's the hardcoded default, see https://www.gnu.org/software/coreutils/quotes.html . – ilkkachu Jul 26 '20 at 07:42
  • Thank for the link.  À la Rob Pike, I consider this harmful, and I know that nobody cares about my opinion.  The GNU document indicates that --quoting-style=literal can be abbreviated --literal or even -N; they are mentioned in the --help output, but I overlooked them. – G-Man Says 'Reinstate Monica' Jul 26 '20 at 16:33
5

For both questions, escape the special characters with \, so they are not interpreted (I assume it is bash). Following your example:

ls Chapitre\ 2\ :\ L\'accès\ au\ système.md
or
gvim Chapitre\ 2\ :\ L\'accès\ au\ système.md.

See the Bash Reference Manual for more info.

Stephen Kitt
  • 434,908
ferranm
  • 173
3

Names with spaces and special chars is always a source of problems. Quoting is always tricky...

gvim "Chapitre 2 : L'accès au système.md" 

is working as you wanted. ls is showing extra quotes (") to clearer delimit the filename, but the quotes are not in the name.

If you do ls | more you will see the names without the protections.



If you really need more complex names (bad idea) you can concatenate quoted block and protected elements(see @ferranm).

Example - a file named a filename with quotes", apostrophes 'and bars (\) may be created as the sum of 3 blocks "a filename with quotes" + '", ' + "apostrophes 'and bars (\)"

touch "a filename with quotes"'", '"apostrophes 'and bars (\)"
JJoao
  • 12,170
  • 1
  • 23
  • 45