Como o Linux lida com vários separadores de caminho consecutivos (/ home //// username /// file)?

111

Estou trabalhando em um script python que passa os locais dos arquivos para um subprocesso scp. Tudo bem, mas estou em uma situação em que posso acabar concatenando um caminho com um nome de arquivo, de modo que haja um duplo ' /no caminho. Eu sei que o bash não se importa se você tiver vários separadores de arquivos, mas estou me perguntando como exatamente isso é corrigido. É o bash que tira /s extras ou isso realmente não importa nunca?

Eu pergunto porque isso me poupará várias linhas de código para verificar se há /s extras enquanto concatenamos. Sei que não é grande coisa, mas também estou curioso. Eu tenho um script bash que tem a linha cd //usr(em vez de cd /usr), o que parece implicar que pode haver um significado para usar vários /s em um caminho

Falmarri
fonte
7
Eu investir em linhas extras de código ...
Stefan
5
Apenas no caso de alguém se importa, o que eu tenho certeza que ninguém faz, eu fiz de fato acabar usando o python joine abspathe tais comandos.
Falmarri 30/09/10

Respostas:

165

São permitidas várias barras e são equivalentes a uma única barra. Na especificação Single Unix (versão 3) , as definições de base §3.266 nome do caminho : "Várias barras sucessivas são consideradas iguais a uma barra".

Há uma exceção: se um nome de caminho começa com exatamente duas barras, ele pode ser tratado de maneira diferente (ref: definições básicas §4.11 resolução de nome de caminho ). O próprio Linux não faz isso, embora alguns aplicativos possam fazer e outro sistema unix-ish (por exemplo, Cygwin).

Um final /no final de um nome de caminho força o nome do caminho a se referir a um diretório. Nas definições de base ( POSIX 1003.1-2001 (Single Unix v3), §4.11 , resolução de nome de caminho , um final /é equivalente a um final /.. As definições de base POSIX 1003.1-2008 (Single Unix v4), §4.12, eliminam o requisito de torná-lo equivalente /., a fim de para lidar com diretórios inexistentes (por exemplo, mkdir foo/é necessário que funcione, enquanto mkdir foo/.que não - veja a lógica da mudança).

Para programas que atuam em uma entrada de diretório, se foohouver um link simbólico para um diretório, a passagem foo/é uma maneira de fazer com que o programa atue no diretório em vez do link simbólico.

¹ Observe que isso se aplica apenas à resolução do nome do caminho, ou seja, ao acessar arquivos. Manipulações de nome de arquivo podem funcionar de maneira diferente. Por exemplo, basenamee dirnameignore as barras finais.

Gilles
fonte
7
O equivalente a /.foi removido após um processo de discussão posterior, pois era ambíguo. De qualquer forma, marcar com +1 esse tipo de informação bem resumida é difícil.
hakre 26/07
17

O sistema operacional também não parece se importar com isso, tendo acabado de experimentar um programa C com um syscall direto para abrir com um // no caminho.

Você pode usar a função da biblioteca python os.path.normpath para normalizá-la, o que evita que você precise varrer a string procurando por extras. Outros idiomas têm funções semelhantes.

http://docs.python.org/library/os.path.html#os.path.normpath

Ivatar
fonte
5
Cuidado com o seguinte comentário na fonte do normpath: Normalize um caminho, por exemplo, A // B, A /./B e A / foo /../B se tornam A / B. Deve-se entender que isso pode alterar o significado do caminho se ele contiver links simbólicos!
Bluehorn
8

Em todos os sistemas Unix que eu vi, é o mesmo que um único /, mas o padrão Unix especifica que

Um nome de caminho que começa com duas barras sucessivas pode ser interpretado de uma maneira definida pela implementação, embora mais de duas barras principais sejam tratadas como uma única barra.

portanto, ele pode ser tratado especialmente, dependendo do seu sistema. (Algumas versões mais antigas do Unix usavam uma vantagem dupla /para acesso remoto ao sistema de arquivos, e ainda pode haver outras que o fazem.)

Fred Foo
fonte
7
Cygwin (embora não seja um UNIX real) se traduz //remote/...em acesso remoto ao sistema de arquivos, provavelmente por consistência com o Windows ' \\remote\....
efêmero
2
Acredito (mas não consigo encontrar uma boa referência no Google) que as APIs compatíveis com Windows POSIX também tratem //remote/...o mesmo que o \\remote\...formato de caminho UNC .
Stephen P
1
Acho que me lembro que os nomes de caminho portáteis do Boost.Filesystem lidam //de uma maneira especial, pois podem falseser absolutos, em conformidade com a especificação Unix / POSIX.
7

Use os.path.joinem Python e você não terá várias barras. A criação de nomes de arquivos concatenando seqüências de caracteres é considerado um estilo pobre do Python.

Neil Mayhew
fonte
Eu concordo, mas o nome do arquivo faz parte de uma cadeia de comando e, em vez de analisar a cadeia de comando para anexar ao nome do arquivo (no final), eu gostaria de anexá-lo.
Falmarri 13/09/10
1
@Falmarri: Você não pode simplesmente acrescentar um nome de arquivo a uma sequência de comandos! Uma sequência de comandos será analisada pelo shell, portanto, caracteres especiais nos nomes dos arquivos precisam ser citados. Portanto, você precisa construir o nome do arquivo e citá-lo corretamente para colocá-lo na cadeia de comando.
Gilles
Este é um projeto realmente específico que eu vou usar. Provavelmente não fui suficientemente claro para justificar não ser robusto quanto a isso. Estou recebendo essa string de caminho de arquivo de uma classe que me fornece um caminho de arquivo com escape correto e tal. E estou anexando-o a um argumento de linha de comando
Falmarri 13/09/10
1
@Falmarri: Portanto, use o normpath para limpar o valor da linha de comando que você não controla e, em seguida, use o join para juntá-los.
Neil Mayhew
Na verdade, foi o que acabei fazendo = \ Não consegui lidar com o caso especial em que me foi dado /muito bem.
Falmarri 20/09/10
3

Não há diferença.

Várias barras são ignoradas (sem efeito), por exemplo:

ls -al //usr///////bin/sed
ChristopheD
fonte
7
Não pode ser, se é exatamente dois e no início; Um nome de caminho que começa com duas barras sucessivas pode ser interpretado de uma maneira definida pela implementação . Na prática, acho que isso é certo e eles são simplesmente ignorados
Michael Mrozek
Obrigado Chris, agradeço o esclarecimento! (infelizmente o login OpenID não está funcionando para mim ou eu votaria-lo)
@Rob Você não está registrado, mas ainda está logado (é rastreado pelo seu cookie). Você deve poder se registrar agora para conectar um OpenID à sua conta, mas poderá votar de qualquer maneira
Michael Mrozek
Obrigado Michael, mas "você precisa fazer o login ou registrar-se para votar". Quando você usa apenas um endereço de e-mail e nome, não tem privilégios totais. E como o OpenID está atingindo o tempo limite e não tenho vontade de criar outra conta, estou sem sorte. Minha culpa por ser preguiçoso, eu acho, mas agradeço a ajuda.
0

Obviamente, você pode normalizar um caminho com possíveis múltiplos / (barras) passando-o através tr -s

NORMALIZED=$(echo "$UNHYGIENIC" | tr -s / /)

... e depois use $NORMALIZED

No entanto, deve ser necessário. Pelo que sei, qualquer kernel UNIX deve ignorar os separadores de caminho simultâneos --- ou tratá-los conceitualmente como ... /./...

Jim Dennis
fonte
"deveria" -> "não deveria".