Eu sempre vejo respostas citando este link dizendo definitivamente "Não analise ls
!" Isso me incomoda por alguns motivos:
Parece que as informações nesse link foram aceitas no atacado com poucas perguntas, embora eu possa detectar pelo menos alguns erros na leitura casual.
Também parece que os problemas mencionados nesse link não provocaram desejo de encontrar uma solução.
Do primeiro parágrafo:
... quando você solicita
[ls]
uma lista de arquivos, há um grande problema: o Unix permite quase qualquer caractere em um nome de arquivo, incluindo espaços em branco, novas linhas, vírgulas, símbolos de pipe e praticamente qualquer outra coisa que você já tentou usar como um arquivo. delimitador, exceto NUL. ...ls
separa nomes de arquivos com novas linhas. Tudo bem até você ter um arquivo com uma nova linha em seu nome. E como eu não conheço nenhuma implementaçãols
que permita que você encerre nomes de arquivos com caracteres NUL em vez de novas linhas, isso nos deixa incapazes de obter uma lista de nomes de arquivos com segurançals
.
Que chatice, certo? Como nunca podemos lidar com uma nova linha terminada conjunto de dados coletados para os dados que podem conter novas linhas? Bem, se as pessoas que respondem às perguntas neste site não faziam esse tipo de coisa diariamente, acho que estávamos com algum problema.
A verdade é que a maioria das ls
implementações realmente fornece uma API muito simples para analisar sua saída e todos nós fazemos isso o tempo todo, mesmo sem perceber. Não apenas você pode terminar um nome de arquivo com nulo, como também pode começar um com nulo ou com qualquer outra sequência arbitrária que desejar. Além disso, você pode atribuir essas seqüências arbitrárias por tipo de arquivo . Por favor considere:
LS_COLORS='lc=\0:rc=:ec=\0\0\0:fi=:di=:' ls -l --color=always | cat -A
total 4$
drwxr-xr-x 1 mikeserv mikeserv 0 Jul 10 01:05 ^@^@^@^@dir^@^@^@/$
-rw-r--r-- 1 mikeserv mikeserv 4 Jul 10 02:18 ^@file1^@^@^@$
-rw-r--r-- 1 mikeserv mikeserv 0 Jul 10 01:08 ^@file2^@^@^@$
-rw-r--r-- 1 mikeserv mikeserv 0 Jul 10 02:27 ^@new$
line$
file^@^@^@$
^@
Veja isso para mais.
Agora, é a próxima parte deste artigo que realmente me emociona:
$ ls -l
total 8
-rw-r----- 1 lhunath lhunath 19 Mar 27 10:47 a
-rw-r----- 1 lhunath lhunath 0 Mar 27 10:47 a?newline
-rw-r----- 1 lhunath lhunath 0 Mar 27 10:47 a space
O problema é que, a partir da saída de
ls
, nem você nem o computador podem dizer quais partes dele constituem um nome de arquivo. São cada palavra? Não. São cada linha? Não. Não há resposta correta para essa pergunta além de: você não pode dizer.Observe também como
ls
às vezes confunde os dados do seu nome de arquivo (no nosso caso, ele transformou o\n
caractere entre as palavras "a" e "nova linha" em um ? Ponto de interrogação ......
Se você deseja iterar sobre todos os arquivos no diretório atual, use um
for
loop e um glob:
for f in *; do
[[ -e $f ]] || continue
...
done
O autor chama de nomes de arquivos ilegíveis quando ls
retorna uma lista de nomes de arquivos que contêm globs de shell e recomenda o uso de um shell glob para recuperar uma lista de arquivos!
Considere o seguinte:
printf 'touch ./"%b"\n' "file\nname" "f i l e n a m e" |
. /dev/stdin
ls -1q
f i l e n a m e
file?name
IFS="
" ; printf "'%s'\n" $(ls -1q)
'f i l e n a m e'
'file
name'
O POSIX define os operandos -1
e -q
ls
assim:
-q
- Força cada instância de caracteres de nome de arquivo não imprimível<tab>
es a serem gravados como o caractere de ponto de interrogação ('?'
). As implementações podem fornecer essa opção por padrão, se a saída for para um dispositivo terminal.
-1
- (O dígito numérico um.) Força a saída a ser uma entrada por linha.
Globbing não tem seus próprios problemas - ?
corresponde a qualquer caractere, portanto vários ?
resultados correspondentes em uma lista correspondem ao mesmo arquivo várias vezes. Isso é facilmente manipulado.
Embora como fazer isso não seja o ponto - afinal, não é preciso muito para fazer e é demonstrado abaixo -, eu estava interessado em saber por que não . Na minha opinião, a melhor resposta para essa pergunta foi aceita. Eu sugiro que você tente se concentrar mais em dizer às pessoas o que elas podem fazer do que o que elas não podem. Você tem muito menos probabilidade, pelo que penso, de se provar errado, pelo menos.
Mas por que tentar? É certo que minha principal motivação era que outros continuavam me dizendo que eu não podia. Sei muito bem que o ls
resultado é tão regular e previsível quanto você deseja, desde que saiba o que procurar. A desinformação me incomoda mais do que a maioria das coisas.
Porém, a verdade é que, com a exceção notável das respostas de Patrick e Wumpus Q. Wumbley (apesar do incrível manuseio deste último) , considero a maioria das informações nas respostas aqui quase sempre corretas - um shell shell é mais simples de usar e geralmente mais eficaz quando se trata de pesquisar o diretório atual do que está analisando ls
. No entanto, elas não são, pelo menos no meu ponto de vista, razão suficiente para justificar a propagação das informações erradas citadas no artigo acima, nem são justificativas aceitáveis para " nunca analisarls
" .
Por favor, note que os resultados inconsistentes da resposta de Patrick são principalmente o resultado dele usando zsh
então bash
. zsh
- por padrão - o $(
comando de divisão de palavras não substitui os )
resultados de maneira portátil. Então, quando ele pergunta para onde foi o restante dos arquivos? a resposta para essa pergunta é que sua concha os comeu. É por isso que você precisa definir a SH_WORD_SPLIT
variável ao usar zsh
e lidar com o código do shell portátil. Considero sua falha em notar isso em sua resposta como terrivelmente enganosa.
A resposta de Wumpus não computa para mim - em um contexto de lista, o ?
personagem é uma bola de fogo. Não sei mais o que dizer.
Para lidar com um caso de vários resultados, você precisa restringir a ganância do globo. A seguir, basta criar uma base de teste com nomes de arquivos horríveis e exibi-la para você:
{ printf %b $(printf \\%04o `seq 0 127`) |
sed "/[^[-b]*/s///g
s/\(.\)\(.\)/touch '?\v\2' '\1\t\2' '\1\n\2'\n/g" |
. /dev/stdin
echo '`ls` ?QUOTED `-m` COMMA,SEP'
ls -qm
echo ; echo 'NOW LITERAL - COMMA,SEP'
ls -m | cat
( set -- * ; printf "\nFILE COUNT: %s\n" $# )
}
RESULTADO
`ls` ?QUOTED `-m` COMMA,SEP
??\, ??^, ??`, ??b, [?\, [?\, ]?^, ]?^, _?`, _?`, a?b, a?b
NOW LITERAL - COMMA,SEP
?
\, ?
^, ?
`, ?
b, [ \, [
\, ] ^, ]
^, _ `, _
`, a b, a
b
FILE COUNT: 12
Agora vou segura cada caractere que não é um /slash
, -dash
, :colon
, ou caractere alfa-numérico em uma glob de shell, em seguida, sort -u
a lista de resultados únicos. Isso é seguro porque ls
já protegemos quaisquer caracteres não imprimíveis para nós. Ver:
for f in $(
ls -1q |
sed 's|[^-:/[:alnum:]]|[!-\\:[:alnum:]]|g' |
sort -u | {
echo 'PRE-GLOB:' >&2
tee /dev/fd/2
printf '\nPOST-GLOB:\n' >&2
}
) ; do
printf "FILE #$((i=i+1)): '%s'\n" "$f"
done
RESULTADO:
PRE-GLOB:
[!-\:[:alnum:]][!-\:[:alnum:]][!-\:[:alnum:]]
[!-\:[:alnum:]][!-\:[:alnum:]]b
a[!-\:[:alnum:]]b
POST-GLOB:
FILE #1: '?
\'
FILE #2: '?
^'
FILE #3: '?
`'
FILE #4: '[ \'
FILE #5: '[
\'
FILE #6: '] ^'
FILE #7: ']
^'
FILE #8: '_ `'
FILE #9: '_
`'
FILE #10: '?
b'
FILE #11: 'a b'
FILE #12: 'a
b'
Abaixo, abordo o problema novamente, mas uso uma metodologia diferente. Lembre-se de que, além de \0
nulo, o /
caractere ASCII é o único byte proibido em um nome de caminho. Coloquei globs de lado aqui e, em vez disso, combine a -d
opção especificada POSIX para ls
e também a -exec $cmd {} +
construção especificada POSIX para find
. Como find
apenas um emitirá naturalmente /
em sequência, o item a seguir obtém facilmente uma lista de arquivos recursiva e delimitada de forma confiável, incluindo todas as informações de dentista para cada entrada. Imagine o que você pode fazer com algo assim:
#v#note: to do this fully portably substitute an actual newline \#v#
#v#for 'n' for the first sed invocation#v#
cd ..
find ././ -exec ls -1ldin {} + |
sed -e '\| *\./\./|{s||\n.///|;i///' -e \} |
sed 'N;s|\(\n\)///|///\1|;$s|$|///|;P;D'
###OUTPUT
152398 drwxr-xr-x 1 1000 1000 72 Jun 24 14:49
.///testls///
152399 -rw-r--r-- 1 1000 1000 0 Jun 24 14:49
.///testls/?
\///
152402 -rw-r--r-- 1 1000 1000 0 Jun 24 14:49
.///testls/?
^///
152405 -rw-r--r-- 1 1000 1000 0 Jun 24 14:49
.///testls/?
`///
...
ls -i
pode ser muito útil - especialmente quando a exclusividade do resultado está em questão.
ls -1iq |
sed '/ .*/s///;s/^/-inum /;$!s/$/ -o /' |
tr -d '\n' |
xargs find
Estes são apenas os meios mais portáteis em que consigo pensar. Com o GNU ls
você pode fazer:
ls --quoting-style=WORD
E por último, aqui está um método muito mais simples de analisarls
que, por acaso, uso com frequência quando preciso de números de inode:
ls -1iq | grep -o '^ *[0-9]*'
Isso apenas retorna números de inode - que é outra opção útil especificada pelo POSIX.
time bash -c 'for i in {1..1000}; do ls -R &>/dev/null; done'
= 3.18s vstime bash -c 'for i in {1..1000}; do echo **/* >/dev/null; done'
= 1.28sstat
minha resposta, pois ela realmente verifica se cada arquivo existe. Sua parte no fundo com ased
coisa não funciona.ls
em primeiro lugar? O que você está descrevendo é muito difícil. Vou precisar desconstruí-lo para entender tudo e sou um usuário relativamente competente. Você não pode esperar que seu Joe médio seja capaz de lidar com algo assim.ls
saída está incorreta foram abordados bem no link original (e em muitos outros lugares). Essa pergunta teria sido razoável se o OP estivesse pedindo ajuda para entendê-lo, mas, em vez disso, o OP está simplesmente tentando provar que seu uso incorreto está correto.parsing ls is bad
. Fazerfor something in $(command)
e confiar na divisão de palavras para obter resultados precisos é ruim para a grande maioria doscommand's
quais não possui saída simples.Respostas:
Não estou absolutamente convencido disso, mas vamos supor, por uma questão de argumento, que você poderia , se estiver preparado para fazer um esforço suficiente, analisar a saída de
ls
maneira confiável, mesmo diante de um "adversário" - alguém que conhece o código que você escreveu e está escolhendo deliberadamente nomes de arquivos criados para quebrá-lo.Mesmo se você pudesse fazer isso, ainda seria uma má idéia .
Bourne shell não é uma boa linguagem. Não deve ser usado para nada complicado, a menos que extrema portabilidade seja mais importante do que qualquer outro fator (por exemplo
autoconf
).Eu afirmo que se você se deparar com um problema em que analisar a saída
ls
parece ser o caminho de menor resistência para um script de shell, isso é uma forte indicação de que o que você está fazendo é muito complicado para o shell e deve reescrever tudo Perl ou Python. Aqui está seu último programa em Python:Isso não tem nenhum problema com caracteres incomuns nos nomes de arquivos - a saída é ambígua da mesma maneira que a saída
ls
é ambígua, mas isso não importaria em um programa "real" (em oposição a uma demonstração como essa), o que seria use o resultado deos.path.join(subdir, f)
diretamente.Igualmente importante, e em forte contraste com o que você escreveu, ainda fará sentido daqui a seis meses e será fácil modificar quando você precisar fazer algo ligeiramente diferente. A título de ilustração, suponha que você descubra a necessidade de excluir arquivos de ponto e backups de editor e processar tudo em ordem alfabética por nome de base:
fonte
for in | for in
fala de recursão? Não tenho certeza. Mesmo que seja, não pode ser mais do que um, certo? Esta é a única resposta que faz sentido para mim até agora.for
loops.os.walk
está fazendo um trabalho pesado nos bastidores, mas você não precisa se preocupar com isso mais do que se preocupar com comols
oufind
trabalhar internamente.os.walk
retorna um objeto gerador . Geradores são a versão das listas lentas do Python. Sempre que o loop for externo itera, o gerador é chamado e "produz" o conteúdo de outro subdiretório. Funcionalidade equivalente no Perl éFile::Find
, se isso ajudar.ls
saída.Esse link é muito referenciado porque as informações são completamente precisas e existem há muito tempo.
ls
substitui caracteres não imprimíveis por caracteres glob sim, mas esses caracteres não estão no nome do arquivo real. Por que isso importa? 2 razões:Por exemplo:
Observe como temos 2 arquivos com a mesma aparência. Como você vai distingui-los se ambos são representados como
a?b
?Há uma diferença aqui. Quando você recebe um glob de volta, como mostrado, esse glob pode corresponder a mais de um arquivo. No entanto, quando você itera pelos resultados correspondentes a um globo, você recebe de volta o arquivo exato, não um globo.
Por exemplo:
Observe como a
xxd
saída mostra que$file
continha os caracteres brutos\t
e\n
, não?
.Se você usar
ls
, você obtém isso:"Eu vou repetir de qualquer maneira, por que não usar
ls
?"Seu exemplo que você deu não funciona realmente. Parece que funciona, mas não funciona.
Estou me referindo a isso:
Eu criei um diretório com vários nomes de arquivos:
Quando executo seu código, recebo o seguinte:
Para onde foram os outros arquivos?
Vamos tentar isso:
Agora vamos usar um globo real:
With bash
O exemplo acima foi com o meu shell normal, zsh. Quando repito o procedimento com o bash, recebo outro conjunto de resultados completamente diferente com o seu exemplo:
Mesmo conjunto de arquivos:
Resultados radicalmente diferentes com o seu código:
Com uma concha glob, funciona perfeitamente bem:
O motivo pelo qual o bash se comporta dessa maneira remonta a um dos pontos que fiz no início da resposta: "O arquivo glob pode corresponder a mais de um arquivo".
ls
está retornando o mesmo glob (a?b
) para vários arquivos; portanto, toda vez que expandimos esse glob, obtemos todos os arquivos correspondentes.Como recriar a lista de arquivos que eu estava usando:
Os de código hexadecimal são caracteres UTF-8 NBSP.
fonte
ls
. Também solicitei que você teste seu código, pois ele não funciona. O que o zsh tem a ver com isso?Vamos tentar simplificar um pouco:
Vejo? Isso já está errado aqui. Existem 3 arquivos, mas o bash está relatando 4. Isso ocorre porque
set
os globs geradosls
são expandidos pelo shell antes de serem passados paraset
. É por isso que você obtém:Ou, se você preferir:
O acima foi executado
bash 4.2.45
.fonte
ls -1qRi | grep -o '^ *[0-9]*'
- isso é analisar als
saída, cara, e é a maneira mais rápida e melhor da qual eu conheço para obter uma lista de números de inodes.A saída de
ls -q
não é nada global. Usa-se?
para significar "Há um personagem aqui que não pode ser exibido diretamente". Globs costumam?
significar "Qualquer caractere é permitido aqui".Os globos têm outros caracteres especiais (
*
e[]
pelo menos, e dentro do[]
par, existem mais). Nenhum deles é escapado porls -q
.Se você tratar a
ls -1q
saída, há um conjunto de globs e os expande, além de receberx
duas vezes, você perderá[x]
completamente. Como um globo, ele não corresponde a si mesmo como uma corda.ls -q
serve para salvar seus olhos e / ou terminal de personagens malucos, não para produzir algo que você possa alimentar de volta para o shell.fonte
A resposta é simples: os casos especiais que
ls
você precisa lidar superam qualquer benefício possível. Esses casos especiais podem ser evitados se você não analisar als
saída.O mantra aqui nunca é confiar no sistema de arquivos do usuário (o equivalente a nunca confiar na entrada do usuário ). Se houver um método que funcione sempre, com 100% de certeza, deve ser o método que você preferir, mesmo que
ls
faça o mesmo, mas com menos certeza. Não vou entrar em detalhes técnicos, uma vez que foram extensivamente abordados por Terdon e Patrick . Sei que, devido aos riscos de usarls
em uma transação importante (e talvez cara) em que meu trabalho / prestígio esteja em jogo, prefiro qualquer solução que não tenha um grau de incerteza, se puder ser evitada.Sei que algumas pessoas preferem algum risco à certeza , mas enviei um relatório de erro .
fonte
A razão pela qual as pessoas dizem que nunca fazem algo não é necessariamente porque absolutamente positivamente não pode ser feito corretamente. Podemos fazê-lo, mas pode ser mais complicado, menos eficiente, tanto no espaço quanto no tempo. Por exemplo, seria perfeitamente correto dizer "Nunca crie um back-end grande para comércio eletrônico no assembly x86".
Agora, agora, ao problema em questão: como você demonstrou, pode criar uma solução que analise sl e forneça o resultado certo - portanto, a correção não é um problema.
É mais complicado? Sim, mas podemos esconder isso atrás de uma função auxiliar.
Então agora para eficiência:
Eficiência de espaço: sua solução depende da
uniq
filtragem de duplicatas, consequentemente, não podemos gerar os resultados preguiçosamente. Então,O(1)
vsO(n)
ou ambos têmO(n)
.Eficiência de tempo: o melhor caso
uniq
usa uma abordagem de hashmap, portanto ainda temos umO(n)
algoritmo no número de elementos adquiridos , provavelmente por serO(n log n)
.Agora, o verdadeiro problema: embora seu algoritmo ainda não pareça tão ruim, tomei muito cuidado ao usar elementos adquiridos e não elementos para n. Porque isso faz uma grande diferença. Digamos que você tenha um arquivo
\n\n
que resultará em um globo para??
corresponder a cada arquivo de 2 caracteres na lista. O engraçado é que se você tiver outro arquivo\n\r
que também resultará??
e também retorne todos os arquivos de 2 caracteres, veja para onde isso está indo? O comportamento exponencial, em vez do linear, certamente se qualifica como "pior comportamento em tempo de execução". É a diferença entre um algoritmo prático e um sobre o qual você escreve artigos em periódicos teóricos da CS.Todo mundo adora exemplos, certo? Aqui vamos nós. Crie uma pasta chamada "test" e use este script python no mesmo diretório em que a pasta está.
A única coisa que isso faz é gerar todos os produtos de comprimento 3 para 7 caracteres. A matemática do ensino médio nos diz que deveriam ser 343 arquivos. Bem, isso deve ser muito rápido para imprimir, então vamos ver:
Agora vamos tentar sua primeira solução, porque realmente não consigo
coisa aqui para trabalhar no Linux mint 16 (que eu acho que fala muito pela usabilidade desse método).
De qualquer forma, como o acima mencionado apenas filtra o resultado depois que o obtém, a solução anterior deve ser pelo menos tão rápida quanto a posterior (não há truques de inode nesse caso - mas esses não são confiáveis, então você desistiria da correção).
Então agora quanto tempo
toma? Bem, eu realmente não sei, leva um tempo para verificar os nomes dos arquivos 343 ^ 343 - depois da morte por calor do universo.
fonte
A intenção declarada do OP abordada
prefácio e justificativa original da resposta † atualizado em 18/05/2015
mikeserv (o OP) afirmou na última atualização de sua pergunta: " Considero uma pena, embora eu tenha feito essa pergunta pela primeira vez, uma fonte de informações erradas e, infelizmente, a resposta mais votada aqui é em grande parte enganosa. "
Bem, tudo bem; Eu sinto que era uma pena que eu gastei tanto tempo tentando descobrir como explicar meu significado apenas para descobrir isso enquanto relia a pergunta. Essa pergunta acabou "[gerando] discussão em vez de respostas" ‡ e acabou pesando cerca de 18K de texto (apenas para a pergunta, apenas para esclarecer), o que seria longo até para um post do blog.
Mas o StackExchange não é sua caixa de sabão e não é seu blog. No entanto, na verdade, você o usou como pelo menos um pouco de ambos. As pessoas acabavam gastando muito tempo respondendo ao seu "To-Point-Out" em vez de responder às perguntas reais das pessoas. Nesse ponto, sinalizarei a pergunta como não adequada para o nosso formato, já que o OP declarou explicitamente que nem sequer pretendia ser uma pergunta.
Neste ponto, não tenho certeza se minha resposta foi direta ou não; provavelmente não, mas foi direcionado para algumas de suas perguntas, e talvez possa ser uma resposta útil para outra pessoa; iniciantes se animam, alguns desses "não" se transformam em "às vezes" quando você é mais experiente. :)
Como uma regra geral...
perdoe as arestas restantes; Como já gastei muito tempo com isso ... em vez de citar o OP diretamente (como originalmente pretendido), tentarei resumir e parafrasear.
[em grande parte reformulado a partir da minha resposta original],
após consideração, acredito que li mal a ênfase que o OP estava colocando nas perguntas que respondi; no entanto, os pontos abordados foram levantados, e eu deixei as respostas em grande parte intactas, pois acredito que elas são objetivas e tratam de questões que eu já vi levantadas em outros contextos, além de conselhos aos iniciantes.
A postagem original perguntava, de várias maneiras, por que vários artigos deram conselhos como "Não analise a
ls
saída" ou "Você nunca deve analisar als
saída" e assim por diante.Minha resolução sugerida para a questão é que instâncias desse tipo de afirmação são simplesmente exemplos de um idioma, redigido de maneiras ligeiramente diferentes, nas quais um quantificador absoluto é associado a um imperativo [por exemplo, «não [nunca] X», «[Você deve] sempre Y», «[nunca deve] Z»] para formar declarações destinadas a serem usadas como regras ou diretrizes gerais, especialmente quando dadas a pessoas novas em um assunto, em vez de serem verdades absolutas. forma aparente dessas declarações, não obstante.
Quando você está começando a aprender um novo assunto, e a menos que tenha uma boa compreensão do porquê de fazer algo diferente, é uma boa idéia simplesmente seguir as regras gerais aceitas sem exceção - a menos que sob orientação de alguém mais experiente você mesmo. Com o aumento da habilidade e experiência, você se torna mais capaz de determinar quando e se uma regra se aplica a qualquer situação específica. Depois de atingir um nível significativo de experiência, você provavelmente entenderá o raciocínio por trás da regra geral e, nesse ponto, poderá começar a usar seu julgamento para determinar se e em que nível as razões por trás da regra se aplicam. nessa situação, e também sobre se há talvez preocupações preponderantes.
E é aí que um especialista, talvez, pode optar por fazer as coisas violando as "Regras". Mas isso não os tornaria menos "As Regras".
E, portanto, para o tópico em questão: na minha opinião, apenas porque um especialista pode violar essa regra sem ser completamente derrubado, não vejo como justificar dizer a um iniciante que "às vezes" é Não há problema em analisar a
ls
saída, porque: não é . Ou, pelo menos, certamente não é certo para um iniciante fazê-lo.Você sempre coloca seus peões no centro; na abertura de uma peça, um movimento; castelo na primeira oportunidade; cavaleiros diante dos bispos; um cavaleiro na beira é sombrio; e sempre verifique se você pode ver seu cálculo até o final! (Opa, desculpe, ficar cansado, isso é para o StackExchange de xadrez.)
Regras devem ser quebradas?
Ao ler um artigo sobre um assunto que é direcionado ou que provavelmente será lido por iniciantes, muitas vezes você verá coisas assim:
Embora essas declarações certamente pareçam estar estabelecendo regras absolutas e atemporais, elas não o são; em vez disso, é uma maneira de declarar regras gerais [aka "diretrizes", "regras básicas", "o básico" etc.) que é pelo menos uma maneira apropriada de indicá-las para os iniciantes que possam estar lendo esses artigos. No entanto, apenas por serem declaradas absolutas, as regras certamente não vinculam profissionais e especialistas [que provavelmente foram os que resumiram essas regras em primeiro lugar, como uma maneira de registrar e transmitir o conhecimento adquirido à medida que lidavam com questões recorrentes. questões em seu ofício particular.]
Essas regras certamente não vão revelar como um especialista lidaria com um problema complexo ou matizado, no qual, digamos, essas regras entram em conflito entre si; ou nas quais as preocupações que levaram à regra simplesmente não se aplicam. Os especialistas não têm medo de (ou não devem ter medo de!) Simplesmente violar regras que eles sabem que não fazem sentido em uma situação específica. Os especialistas estão constantemente lidando com o equilíbrio de vários riscos e preocupações em seu ofício, e devem frequentemente usar seu julgamento para optar por violar esse tipo de regra, tendo que equilibrar vários fatores e não poder confiar apenas em uma tabela de regras a seguir. Tomemos
Goto
como exemplo: houve um longo e recorrente debate sobre se eles são prejudiciais. (Sim, nunca use gotos.; D)Uma proposição modal
Uma característica estranha, pelo menos em inglês, e imagino em muitas outras línguas, de regras gerais, é que elas são declaradas da mesma forma que uma proposição modal, mas os especialistas em um campo estão dispostos a dar uma regra geral para uma situação, sabendo o tempo todo que eles violarão a regra quando apropriado. Claramente, portanto, essas declarações não são equivalentes às mesmas declarações na lógica modal.
É por isso que digo que eles devem ser simplesmente idiomáticos. Em vez de realmente ser uma situação de "nunca" ou "sempre", essas regras geralmente servem para codificar diretrizes gerais que tendem a ser apropriadas para uma ampla gama de situações e que, quando os iniciantes as seguem cegamente, provavelmente resultam em melhores resultados do que o iniciante escolhendo ir contra eles sem uma boa razão. Às vezes, eles codificam regras que simplesmente resultam em resultados abaixo do padrão, em vez de falhas definitivas que acompanham escolhas incorretas ao ir contra as regras.
Portanto, regras gerais não são as proposições modais absolutas que parecem estar na superfície, mas são uma maneira abreviada de fornecer à regra um clichê padrão implícito, algo como o seguinte:
onde, é claro, você pode substituir "nunca analisar a
ls
saída" no lugar de $ {RULE}. :)Oh sim! E quanto à análise de
ls
saída?Bem, então, considerando tudo isso ... eu acho que é bem claro que essa regra é boa. Primeiro de tudo, a regra real deve ser entendida como idiomática, conforme explicado acima ...
Além disso, não é apenas necessário que você seja muito bom com o script de shell para saber se ele pode ser quebrado, em alguns casos específicos. Também é preciso muita habilidade para dizer que você errou ao tentar quebrá-lo nos testes! E digo com confiança que uma grande maioria do público provável desses artigos (dando conselhos como "Não analise o resultado de
ls
!") Não pode fazer essas coisas , e aqueles que têm essa habilidade provavelmente perceberão que eles descobrem por conta própria e ignoram a regra de qualquer maneira.Mas ... basta olhar para esta pergunta, e como até as pessoas que provavelmente possuem essa habilidade pensaram que era uma má decisão fazê-lo; e quanto esforço o autor da pergunta gastou apenas para chegar a um ponto do melhor exemplo atual! Garanto a você que, em um problema, 99% das pessoas errariam e com resultados potencialmente muito ruins! Mesmo que o método decidido seja bom; até que (ou outra) a
ls
ideia de análise seja adotada pelo pessoal de TI / desenvolvedor como um todo, resista a muitos testes (especialmente o teste do tempo) e, finalmente, consiga passar para um status de 'técnica comum', é provável que um muitas pessoas podem tentar e errar ... com consequências desastrosas.Então, vou reiterar mais uma vez .... que, especialmente neste caso , que é por isso que " não analisar
ls
saída!" é decididamente o caminho certo para expressá-lo.[ATUALIZAÇÃO 18/05/2014: raciocínio esclarecido para a resposta (acima) para responder a um comentário do OP; a seguinte adição é uma resposta às adições do OP à pergunta de ontem]
[ATUALIZAÇÃO 10/11/2014: cabeçalhos adicionados e conteúdo reorganizado / refatorado; e também: reformatação, reformulação, esclarecimento e um ... "conciso-seying" ... eu pretendia que isso fosse simplesmente uma limpeza, embora tenha se transformado em um retrabalho. eu o tinha deixado em um estado lastimável, então tentei principalmente dar-lhe alguma ordem. eu senti que era importante deixar intacta a primeira seção; portanto, apenas duas pequenas alterações, redundantes 'mas' removidas e 'isso' enfatizadas.]
† Eu pretendia isso originalmente apenas como um esclarecimento sobre o meu original; mas decidiu outras adições após a reflexão
‡ consulte https://unix.stackexchange.com/tour para obter orientações sobre postagens
fonte
ls
!' é o conselho correto: 1. demonstre (para sua satisfação) que todo caso de uso em que se pode analisar als
saída tem outra solução disponível, superior de alguma forma, sem fazê-lo. 2. mostre que, nos casos citados, a afirmação não é literal.ls
é um utilitário de computador - você pode analisar a saída do computador.É possível analisar a saída
ls
em certos casos? Certo. A idéia de extrair uma lista de números de inode de um diretório é um bom exemplo - se você souber que sua implementação éls
compatível-q
e, portanto, cada arquivo produzirá exatamente uma linha de saída, e tudo que você precisa são os números de inode, analisando-osls -Rai1q
a saída é certamente uma solução possível. Obviamente, se o autor não tivesse visto conselhos como "Nunca analise a saída de ls" antes, provavelmente não pensaria em nomes de arquivos com novas linhas e provavelmente deixaria de fora o 'q' como resultado. o código seria sutilmente quebrado nesse caso extremo - portanto, mesmo nos casos em quels
a saída da análise for razoável, esse conselho ainda será útil.O ponto mais amplo é que, quando um novato para shell script tenta ter uma figura roteiro out (por exemplo) o que é o maior arquivo em um diretório, ou o que é o arquivo modificado mais recentemente em um diretório, seu primeiro instinto é para analisar
ls
's saída - compreensível, porquels
é um dos primeiros comandos que um novato aprende.Infelizmente, esse instinto está errado e essa abordagem está quebrada. Ainda mais infelizmente, ele está sutilmente quebrado - funcionará na maioria das vezes, mas falha em casos extremos que talvez possam ser explorados por alguém com conhecimento do código.
O novato pode pensar
ls -s | sort -n | tail -n 1 | awk '{print $2}'
em uma maneira de obter o maior arquivo em um diretório. E funciona, até que você tenha um arquivo com um espaço no nome.OK, e daí
ls -s | sort -n | tail -n 1 | sed 's/[^ ]* *[0-9]* *//'
? Funciona bem até você ter um arquivo com uma nova linha no nome.A adição
-q
dels
argumentos nos ajuda quando há uma nova linha no nome do arquivo? Pode parecer, até que você tenha 2 arquivos diferentes que contêm um caractere não imprimível no mesmo local no nome do arquivo e, em seguidals
, a saída não permite distinguir qual deles foi o maior. Pior, para expandir o "?", Ele provavelmente recorre ao de seu shelleval
- o que causará problemas se ele acessar um arquivo chamado, por exemplo,Será que
--quoting-style=shell
ajuda (se ols
mesmo suporta-lo)? Não, ainda exibe? para caracteres não imprimíveis, ainda é ambíguo qual das várias correspondências foi a maior.--quoting-style=literal
? Não, o mesmo.--quoting-style=locale
ou--quoting-style=c
pode ajudar se você apenas precisar imprimir o nome do arquivo maior sem ambiguidade, mas provavelmente não se precisar fazer algo com o arquivo posteriormente - seria um monte de código para desfazer a citação e voltar ao nome real do arquivo, que você pode passar para, digamos, gzip.E no final de todo esse trabalho, mesmo que o que ele tenha seja seguro e correto para todos os nomes de arquivos possíveis, é ilegível e impossível de manter, e poderia ter sido feito com muito mais facilidade, segurança e legibilidade em python, perl ou ruby.
Ou mesmo usando outras ferramentas de shell - no topo da minha cabeça, acho que isso deve funcionar:
E deve ser pelo menos tão portátil quanto
--quoting-style
é.fonte