How to Use "/" in a Filename

Is it possible to use / in a filename?

The answer is that you can't, unless your filesystem has a bug. Here's why:

There is a system call for renaming your file defined in fs/namei.c called renameat:

SYSCALL_DEFINE4(renameat, int, olddfd, const char __user *, oldname,
int, newdfd, const char __user *, newname)

When the system call gets invoked, it does a path lookup (do_path_lookup) on the name. Keep tracing this, and we get to link_path_walk which has this:

static int link_path_walk(const char *name, struct nameidata *nd)
{
struct path next;
int err;
unsigned int lookup_flags = nd->flags;

while (*name=='/')
name++;
if (!*name)
return 0;
...

This code applies to any file system. What's this mean? It means that if you try to pass a parameter with an actual '/' character as the name of the file using traditional means, it will not do what you want. There is no way to escape the character. If a filesystem "supports" this, it's because they either:

  • Use a unicode character or something that looks like a slash but isn't.
  • They have a bug.

Furthermore, if you did go in and edit the bytes to add a slash character into a file name, bad things would happen. That's because you could never refer to this file by name :( since anytime you did, Linux would assume you were referring to a nonexistent directory. Using the 'rm *' technique would not work either, since bash simply expands that to the filename. Even rm -rf wouldn't work, since a simple strace reveals how things go on under the hood (shortened):

$ ls testdir
myfile2 out
$ strace -vf rm -rf testdir
...
unlinkat(3, "myfile2", 0) = 0
unlinkat(3, "out", 0) = 0
fcntl(3, F_GETFD) = 0x1 (flags FD_CLOEXEC)
close(3) = 0
unlinkat(AT_FDCWD, "testdir", AT_REMOVEDIR) = 0
...

Notice that these calls to unlinkat would fail because they need to refer to the files by name.

Allowed characters in filename

You should start with the Wikipedia Filename page. It has a decent-sized table (Comparison of filename limitations), listing the reserved characters for quite a lot of file systems.

It also has a plethora of other information about each file system, including reserved file names such as CON under MS-DOS. I mention that only because I was bitten by that once when I shortened an include file from const.h to con.h and spent half an hour figuring out why the compiler hung.

Turns out DOS ignored extensions for devices so that con.h was exactly the same as con, the input console (meaning, of course, the compiler was waiting for me to type in the header file before it would continue).

how save a file in Python whose name has slashes in it

Yeah, there are some convoluted ways of keeping the "slash," but they probably aren't worth it (i.e. using a unicode division slash).

layers = ['conv1/7x7_s2','pool1/3x3_s2']
for idx, layer in enumerate(layers):
print(layer.replace('/', '_'))
# or maybe this might work?
# print(layer.replace('/', u"\u2215"))

Turn a string into a valid filename?

You can look at the Django framework for how they create a "slug" from arbitrary text. A slug is URL- and filename- friendly.

The Django text utils define a function, slugify(), that's probably the gold standard for this kind of thing. Essentially, their code is the following.

import unicodedata
import re

def slugify(value, allow_unicode=False):
"""
Taken from https://github.com/django/django/blob/master/django/utils/text.py
Convert to ASCII if 'allow_unicode' is False. Convert spaces or repeated
dashes to single dashes. Remove characters that aren't alphanumerics,
underscores, or hyphens. Convert to lowercase. Also strip leading and
trailing whitespace, dashes, and underscores.
"""
value = str(value)
if allow_unicode:
value = unicodedata.normalize('NFKC', value)
else:
value = unicodedata.normalize('NFKD', value).encode('ascii', 'ignore').decode('ascii')
value = re.sub(r'[^\w\s-]', '', value.lower())
return re.sub(r'[-\s]+', '-', value).strip('-_')

And the older version:

def slugify(value):
"""
Normalizes string, converts to lowercase, removes non-alpha characters,
and converts spaces to hyphens.
"""
import unicodedata
value = unicodedata.normalize('NFKD', value).encode('ascii', 'ignore')
value = unicode(re.sub('[^\w\s-]', '', value).strip().lower())
value = unicode(re.sub('[-\s]+', '-', value))
# ...
return value

There's more, but I left it out, since it doesn't address slugification, but escaping.

How do I create files with special characters in Linux?

You need to escape special characters with the backslash symbol (\).


This command will create a file named "\?$*'KwaMe'*$?\":

touch \"\\\?\$\*\'KwaMe\'\*\$\?\\\"


Explanation

  1. Double your \, like this: \\, so that your shell does not interpret the backslashes from your filename as escape characters.
  2. Escape " and ', like this: \", \', so that your shell interprets the double quotes as part of the filename.
  3. Escape $, like this: \$, otherwise your shell will think you're using a variable.
  4. Escape ? and *, like this: \?, \*, to prevent filename expansion.

C# Save file with / in name

You're out of luck. A forward slash can't be part of a file name.

You need to escape it somehow (i.e. change the name but provide a way of changing it back), but there isn't really a conventional way of doing that.

I've seen % been used for this purpose, with %% used to denote a single %, and something like %f for a forward slash, %b for a backslash, etc.

how to filter the filename based on special character in html page in angular?

Sounds like a perfect use case for a custom pipe.

You could create a custom pipe like this:

import { Pipe, PipeTransform } from '@angular/core';

@Pipe({
name: 'nameWithoutHash'
})
export class NameWithoutHashPipe implements PipeTransform {

transform(fullName: any, args?: any): any {
return fullName.split('|')[1];
}

}

You could then use it like this:

<mat-list role="list">
<mat-list-item role="listitem" *ngFor="let item of uploadedFiles">
<div class="list-files">
<span>{{item | nameWithoutHash}}</span>
<div class="btn-custom" (click)="delete(item)"> Delete</div>
</div>
</mat-list-item>
</mat-list>

Here's a working Sample Code Demo for your ref.

how to use the name of the input file in sed replace

I'm not sure you can reference the filename using sed although I could be wrong. You would probably use a shell hack. A better aproach to substitute all occurrences of temp with the filename would be the following awk script:

$ awk '{gsub(/temp/,FILENAME)}1' file

What characters are forbidden in Windows and Linux directory names?

A “comprehensive guide” of forbidden filename characters is not going to work on Windows because it reserves filenames as well as characters. Yes, characters like
* " ? and others are forbidden, but there are a infinite number of names composed only of valid characters that are forbidden. For example, spaces and dots are valid filename characters, but names composed only of those characters are forbidden.

Windows does not distinguish between upper-case and lower-case characters, so you cannot create a folder named A if one named a already exists. Worse, seemingly-allowed names like PRN and CON, and many others, are reserved and not allowed. Windows also has several length restrictions; a filename valid in one folder may become invalid if moved to another folder. The rules for
naming files and folders
are on the Microsoft docs.

You cannot, in general, use user-generated text to create Windows directory names. If you want to allow users to name anything they want, you have to create safe names like A, AB, A2 et al., store user-generated names and their path equivalents in an application data file, and perform path mapping in your application.

If you absolutely must allow user-generated folder names, the only way to tell if they are invalid is to catch exceptions and assume the name is invalid. Even that is fraught with peril, as the exceptions thrown for denied access, offline drives, and out of drive space overlap with those that can be thrown for invalid names. You are opening up one huge can of hurt.



Related Topics



Leave a reply



Submit