Constantemente veo respuestas que citan este enlace que dice definitivamente "¡No analizar ls
!" Esto me molesta por un par de razones:
Parece que la información en ese enlace ha sido aceptada al por mayor con pocas preguntas, aunque puedo detectar al menos algunos errores en la lectura informal.
También parece que los problemas establecidos en ese enlace no han provocado el deseo de encontrar una solución.
Del primer párrafo:
... cuando solicita
[ls]
una lista de archivos, hay un gran problema: Unix permite casi cualquier carácter en un nombre de archivo, incluidos espacios en blanco, líneas nuevas, comas, símbolos de barra y prácticamente cualquier otra cosa que alguna vez intente usar como delimitador excepto NUL. ...ls
separa los nombres de archivo con nuevas líneas. Esto está bien hasta que tenga un archivo con una nueva línea en su nombre. Y dado que no conozco ninguna implementaciónls
que le permita terminar los nombres de archivo con caracteres NUL en lugar de líneas nuevas, esto no nos permite obtener una lista de nombres de archivo de forma segurals
.
Bummer, ¿verdad? Como siempre podemos manejar una línea nueva terminada conjunto de datos que figuran para los datos que puedan contener saltos de línea? Bueno, si las personas que responden preguntas en este sitio web no hacen este tipo de cosas a diario, podría pensar que estamos en problemas.
Sin embargo, la verdad es que la mayoría de las ls
implementaciones en realidad proporcionan una API muy simple para analizar su salida y todos lo hemos estado haciendo todo el tiempo sin siquiera darnos cuenta. No solo puede finalizar un nombre de archivo con nulo, también puede comenzar uno con nulo o con cualquier otra cadena arbitraria que desee. Además, puede asignar estas cadenas arbitrarias por tipo de archivo . Por favor considera:
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^@^@^@$
^@
Mira esto para más.
Ahora es la siguiente parte de este artículo lo que realmente me atrapa:
$ 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
El problema es que, a partir de la salida de
ls
, ni usted ni la computadora pueden saber qué partes constituyen un nombre de archivo. ¿Es cada palabra? No. ¿Es cada línea? No. No hay una respuesta correcta a esta pregunta que no sea: no se puede saber.Observe también cómo a
ls
veces confunde los datos de su nombre de archivo (en nuestro caso, convirtió el\n
carácter entre las palabras "a" y "nueva línea" en un signo de interrogación ......
Si solo desea iterar sobre todos los archivos en el directorio actual, use un
for
bucle y un globo:
for f in *; do
[[ -e $f ]] || continue
...
done
¡El autor lo llama nombres de archivo confusos cuando ls
devuelve una lista de nombres de archivo que contienen globos de shell y luego recomienda usar un globo de shell para recuperar una lista de archivos!
Considera lo siguiente:
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'
POSIX define los operandos -1
y -q
ls
así:
-q
- Forzar que cada instancia de caracteres de nombre de archivo no imprimibles ys<tab>
se escriban como el signo de interrogación ('?'
). Las implementaciones pueden proporcionar esta opción por defecto si la salida es a un dispositivo terminal.
-1
- (El dígito numérico uno.) Fuerza la salida a ser una entrada por línea.
Globbing no está exento de problemas: ?
coincide con cualquier carácter, por lo que múltiples ?
resultados coincidentes en una lista coincidirán con el mismo archivo varias veces. Eso es fácil de manejar.
Aunque la forma de hacer esto no es el punto, después de todo, no se necesita mucho para hacer y se demuestra a continuación, estaba interesado en por qué no . Según lo considero, la mejor respuesta a esa pregunta ha sido aceptada. Te sugiero que trates de concentrarte más a menudo en decirle a la gente lo que pueden hacer que en lo que no pueden. Es mucho menos probable, como creo, que se demuestre que está equivocado al menos.
Pero, ¿por qué intentarlo? Es cierto que mi motivación principal era que otros me decían que no podía. Sé muy bien que la ls
salida es tan regular y predecible como podrías desear, siempre y cuando sepas qué buscar. La información errónea me molesta más que la mayoría de las cosas.
Sin embargo, la verdad es que, con la notable excepción de las respuestas de Patrick y Wumpus Q. Wumbley (a pesar del increíble manejo de este último) , considero que la mayoría de la información en las respuestas aquí es en su mayoría correcta: un globo de concha es más fácil de usar y generalmente más efectivo cuando se trata de buscar en el directorio actual que el análisis ls
. Sin embargo, no son, al menos en mi opinión, razones suficientes para justificar la propagación de la información errónea citada en el artículo anterior ni son una justificación aceptable para " nunca analizarls
" .
Tenga en cuenta que los resultados inconsistentes de la respuesta de Patrick son principalmente el resultado de su uso en zsh
ese momento bash
. zsh
- por defecto - el $(
comando de división de palabras no sustituye los )
resultados de manera portátil. Entonces, cuando pregunta a dónde se fue el resto de los archivos. la respuesta a esa pregunta es que tu caparazón se los comió. Esta es la razón por la que necesita establecer la SH_WORD_SPLIT
variable al usar zsh
y tratar con código shell portátil. Considero que no haber notado esto en su respuesta es terriblemente engañoso.
La respuesta de Wumpus no calcula para mí: en un contexto de lista, el ?
personaje es un globo de shell. No sé cómo decir eso.
Para manejar un caso de resultados múltiples, debe restringir la codicia del globo. Lo siguiente solo creará una base de prueba de nombres de archivos horribles y lo mostrará por usted:
{ 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" $# )
}
SALIDA
`ls` ?QUOTED `-m` COMMA,SEP
??\, ??^, ??`, ??b, [?\, [?\, ]?^, ]?^, _?`, _?`, a?b, a?b
NOW LITERAL - COMMA,SEP
?
\, ?
^, ?
`, ?
b, [ \, [
\, ] ^, ]
^, _ `, _
`, a b, a
b
FILE COUNT: 12
Ahora voy a salvo cada carácter que no es un /slash
, -dash
, :colon
, o carácter alfanumérico en un pegote cáscara continuación sort -u
la lista de resultados únicos. Esto es seguro porque ls
ya nos ha guardado los caracteres no imprimibles. Reloj:
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
SALIDA:
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'
A continuación, vuelvo a abordar el problema pero utilizo una metodología diferente. Recuerde que, además de \0
nulo, el /
carácter ASCII es el único byte prohibido en un nombre de ruta. Puse los globos a un lado aquí y en su lugar combiné la -d
opción especificada POSIX para ls
y la -exec $cmd {} +
construcción también POSIX especificada para find
. Debido a find
que solo emitirá naturalmente uno /
en secuencia, lo siguiente proporciona fácilmente una lista de archivos recursiva y delimitada de manera confiable que incluye toda la información de rechazo para cada entrada. Solo imagine lo que podría hacer con algo como esto:
#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
puede ser muy útil, especialmente cuando la unicidad del resultado está en duda.
ls -1iq |
sed '/ .*/s///;s/^/-inum /;$!s/$/ -o /' |
tr -d '\n' |
xargs find
Estos son solo los medios más portátiles que se me ocurren. Con GNU ls
podrías hacer:
ls --quoting-style=WORD
Y por último, aquí hay un método mucho más simple de análisisls
que uso con bastante frecuencia cuando necesito números de inodo:
ls -1iq | grep -o '^ *[0-9]*'
Eso solo devuelve números de inodo, que es otra práctica opción especificada por 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
en mi respuesta, ya que realmente comprueba que cada archivo existe. Su parte inferior con lased
cosa no funciona.ls
en primer lugar? Lo que estás describiendo es muy difícil. Necesitaré deconstruirlo para comprenderlo todo y soy un usuario relativamente competente. No puedes esperar que tu Joe promedio pueda lidiar con algo como esto.ls
resultado del análisis es incorrecto se cubrieron bien en el enlace original (y en muchos otros lugares). Esta pregunta habría sido razonable si OP estuviera pidiendo ayuda para entenderla, pero en cambio OP simplemente está tratando de demostrar que su uso incorrecto está bien.parsing ls is bad
. Hacerfor something in $(command)
y confiar en la división de palabras para obtener resultados precisos es malo para la gran mayoría de loscommand's
cuales no tienen una salida simple.Respuestas:
No estoy del todo convencido de esto, pero supongamos por el argumento de que , si está preparado para hacer un esfuerzo suficiente, podría analizar el resultado de
ls
manera confiable, incluso frente a un "adversario": alguien que conoce el código que escribió y elige deliberadamente nombres de archivo diseñados para romperlo.Incluso si pudieras hacer eso, sería una mala idea .
Bourne Shell no es un buen lenguaje. No debe usarse para nada complicado, a menos que la portabilidad extrema sea más importante que cualquier otro factor (p
autoconf
. Ej .).Afirmo que si se enfrenta a un problema en el que analizar la salida de
ls
parece ser el camino de menor resistencia para un script de shell, eso es una fuerte indicación de que lo que sea que esté haciendo es demasiado complicado para shell y debe volver a escribir todo en Perl o Python. Aquí está su último programa en Python:Esto no tiene ningún problema con los caracteres inusuales en los nombres de archivo: la salida es ambigua de la misma manera que la salida de
ls
es ambigua, pero eso no importaría en un programa "real" (a diferencia de una demostración como esta), que usar el resultado deos.path.join(subdir, f)
directamente.Igualmente importante, y en marcado contraste con lo que escribiste, aún tendrá sentido dentro de seis meses, y será fácil de modificar cuando lo necesites para hacer algo ligeramente diferente. A modo de ilustración, suponga que descubre la necesidad de excluir archivos de puntos y copias de seguridad del editor, y procesar todo en orden alfabético por nombre base:
fuente
for in | for in
Eso habla de recursión? No estoy seguro. Incluso si es así, no puede ser más de uno, ¿verdad? Esta es la única respuesta que tiene sentido para mí hasta ahora.for
bucles anidados .os.walk
está haciendo un trabajo muy pesado detrás de escena, pero no tiene que preocuparse más de lo que tiene que preocuparse por cómols
ofind
trabajar internamente.os.walk
devuelve un objeto generador . Los generadores son la versión de Python de las listas perezosas. Cada vez que el bucle for externo se repite, se invoca el generador y "produce" el contenido de otro subdirectorio. Funcionalidad equivalente en Perl esFile::Find
, si eso ayuda.ls
salida.Se hace mucha referencia a ese enlace porque la información es completamente precisa y ha estado allí durante mucho tiempo.
ls
reemplaza los caracteres no imprimibles con caracteres globales sí, pero esos caracteres no están en el nombre de archivo real. ¿Por qué importa esto? 2 razones:Por ejemplo:
Observe cómo tenemos 2 archivos que se ven exactamente iguales. ¿Cómo los distinguirá si ambos están representados como
a?b
?Hay una diferencia aquí. Cuando recuperas un globo, como se muestra, ese globo puede coincidir con más de un archivo. Sin embargo, cuando itera por los resultados que coinciden con un glob, obtiene el archivo exacto, no un glob.
Por ejemplo:
Observe cómo la
xxd
salida muestra que$file
contenía los caracteres sin formato\t
y\n
no?
.Si usas
ls
, obtienes esto en su lugar:"Voy a repetir de todos modos, ¿por qué no usar
ls
?"Tu ejemplo que diste en realidad no funciona. Parece que funciona, pero no funciona.
Me refiero a esto:
He creado un directorio con un montón de nombres de archivo:
Cuando ejecuto su código, obtengo esto:
¿A dónde fue el resto de los archivos?
Probemos esto en su lugar:
Ahora usemos un globo real:
Con bash
El ejemplo anterior fue con mi shell normal, zsh. Cuando repito el procedimiento con bash, obtengo otro conjunto de resultados completamente diferente con su ejemplo:
Mismo conjunto de archivos:
Resultados radicalmente diferentes con su código:
Con un globo de concha, funciona perfectamente bien:
La razón por la que bash se comporta de esta manera se remonta a uno de los puntos que mencioné al principio de la respuesta: "El archivo glob podría coincidir con más de un archivo".
ls
está devolviendo el mismo glob (a?b
) para varios archivos, por lo que cada vez que expandimos este glob, obtenemos todos los archivos que coinciden.Cómo recrear la lista de archivos que estaba usando:
Los códigos hexadecimales son caracteres UTF-8 NBSP.
fuente
ls
. También solicité que probaras tu código ya que no funciona. ¿Qué tiene que ver zsh con todo esto?Probemos y simplifiquemos un poco:
¿Ver? Eso ya está mal allí. Hay 3 archivos pero bash está informando 4. Esto se debe a que
set
se le están dando los globos generados por losls
cuales el shell expande antes de pasarlosset
. Por eso obtienes:O, si lo prefieres:
Lo anterior se ejecutó
bash 4.2.45
.fuente
ls -1qRi | grep -o '^ *[0-9]*'
: esa es lals
salida de análisis , hombre, y es la mejor y más rápida forma de obtener una lista de números de inodo.La salida de
ls -q
no es un problema en absoluto. Suele?
significar "Aquí hay un personaje que no se puede mostrar directamente". Los globos suelen?
significar "Cualquier personaje está permitido aquí".Los globos tienen otros caracteres especiales (
*
y[]
al menos, y dentro del[]
par hay más). Ninguno de ellos se escapals -q
.Si trata la
ls -1q
salida, hay un conjunto de globos y los expande, no solo obtendráx
dos veces, sino que se perderá por[x]
completo. Como glob, no se combina como una cadena.ls -q
está destinado a salvar sus ojos y / o terminal de personajes locos, no para producir algo que pueda alimentar al shell.fuente
La respuesta es simple: los casos especiales
ls
que tiene que manejar superan cualquier beneficio posible. Estos casos especiales se pueden evitar si no analiza lals
salida.El mantra aquí es nunca confiar en el sistema de archivos del usuario (el equivalente a nunca confiar en la entrada del usuario ). Si hay un método que funcionará siempre, con 100% de certeza, debería ser el método que prefiera, incluso si
ls
hace lo mismo pero con menos certeza. No voy a entrar en detalles técnicos, ya que fueron cubiertos por terdon y Patrick ampliamente. Sé que debido a los riesgos de usarls
en una transacción importante (y tal vez costosa) donde mi trabajo / prestigio está en juego, preferiré cualquier solución que no tenga un grado de incertidumbre si se puede evitar.Sé que algunas personas prefieren cierto riesgo sobre la certeza , pero he presentado un informe de error .
fuente
La razón por la que la gente dice que nunca hagas algo no es necesariamente porque no se puede hacer de manera absolutamente positiva. Es posible que podamos hacerlo, pero puede ser más complicado, menos eficiente tanto en el espacio como en el tiempo. Por ejemplo, estaría perfectamente bien decir "Nunca construyas un backend de comercio electrónico grande en ensamblado x86".
Ahora, al tema en cuestión: como ha demostrado, puede crear una solución que analice ls y proporcione el resultado correcto, por lo que la corrección no es un problema.
¿Es más complicado? Sí, pero podemos ocultar eso detrás de una función auxiliar.
Así que ahora a la eficiencia:
Eficiencia espacial: su solución se basa en
uniq
filtrar duplicados, por lo tanto, no podemos generar los resultados de manera perezosa. Entonces, oO(1)
vs.O(n)
o ambos tienenO(n)
.Eficiencia en el tiempo: Best case
uniq
utiliza un enfoque de hashmap, por lo que todavía tenemos unO(n)
algoritmo en la cantidad de elementos adquiridos , aunque probablemente lo seaO(n log n)
.Ahora el verdadero problema: si bien su algoritmo todavía no se ve tan mal, tuve mucho cuidado de usar elementos adquiridos y no elementos para n. Porque eso hace una gran diferencia. Supongamos que tiene un archivo
\n\n
que resultará en un globo para??
que coincida con cada archivo de 2 caracteres en la lista. Curiosamente, si tiene otro archivo\n\r
que también dará como resultado??
y también devolverá los 2 archivos de caracteres ... ¿ve a dónde va esto? El comportamiento exponencial en lugar de lineal ciertamente califica como "peor comportamiento en tiempo de ejecución" ... es la diferencia entre un algoritmo práctico y uno sobre el que escribes artículos en revistas teóricas de CS.Todo el mundo ama los ejemplos, ¿verdad? Aquí vamos. Haga una carpeta llamada "prueba" y use este script de Python en el mismo directorio donde está la carpeta.
Lo único que hace es generar todos los productos de longitud 3 para 7 caracteres. Las matemáticas de la secundaria nos dicen que deberían ser 343 archivos. Bueno, eso debería ser realmente rápido de imprimir, así que veamos:
Ahora intentemos su primera solución, porque realmente no puedo entender esto
aquí para trabajar en Linux mint 16 (que creo que dice mucho sobre la usabilidad de este método).
De todos modos, ya que lo anterior solo filtra el resultado una vez que lo obtiene, la solución anterior debe ser al menos tan rápida como la posterior (no hay trucos de inodo en ese, pero no son confiables, por lo que renunciarías a la corrección).
Entonces, ¿cuánto tiempo dura
¿tomar? Bueno, realmente no lo sé, lleva un tiempo comprobar los nombres de los archivos 343 ^ 343: te lo diré después de la muerte por el calor del universo.
fuente
Intención declarada de OP dirigida
Prefacio y justificación de la respuesta original † actualizado el 18/05/2015
mikeserv (OP) declaró en la última actualización de su pregunta: "Sin embargo, considero una pena que primero hice esta pregunta para señalar una fuente de información errónea y, desafortunadamente, la respuesta más votada aquí es en gran parte engañosa. "
Bueno esta bien; Creo que fue más bien una vergüenza que pasé mucho tiempo tratando de encontrar la manera de explicar lo que quiero decir sólo para encontrar que ya puedo volver a leer la pregunta. Esta pregunta terminó "[generando] discusión en lugar de respuestas" ‡ y terminó con un peso de ~ 18K de texto (solo para la pregunta, para ser claros), lo que sería largo incluso para una publicación de blog.
Pero StackExchange no es su caja de jabón, y no es su blog. Sin embargo, en efecto, lo ha usado como al menos un poco de ambos. Las personas terminaron pasando mucho tiempo respondiendo a su "To-Point-Out" en lugar de responder las preguntas reales de las personas. En este punto, marcaré la pregunta como no adecuada para nuestro formato, dado que el OP ha declarado explícitamente que ni siquiera tenía la intención de ser una pregunta.
En este punto, no estoy seguro de si mi respuesta fue correcta o no; probablemente no, pero se dirigió a algunas de sus preguntas, y tal vez pueda ser una respuesta útil para otra persona; los principiantes se animan, algunos de esos "no" se convierten en "hacer a veces" una vez que tenga más experiencia. :)
Como regla general...
por favor, perdona los bordes ásperos restantes; Ya he pasado demasiado tiempo en esto ... en lugar de citar el OP directamente (como se pretendía originalmente), intentaré resumir y parafrasear.
[revisado en gran medida desde mi respuesta original]
después de considerarlo, creo que leí mal el énfasis que el OP estaba poniendo en las preguntas que respondí; Sin embargo, los puntos tratados fueron criados, y he dejado las respuestas en gran parte intacto, ya que creo que fueran a-la-punto y para abordar los problemas que he visto criado en otros contextos también en relación con consejos a los principiantes.
La publicación original preguntaba, de varias maneras, por qué varios artículos daban consejos como "No analizar la
ls
salida" o "Nunca debe analizar lals
salida", y así sucesivamente.Mi resolución sugerida para el problema es que las instancias de este tipo de afirmación son simplemente ejemplos de una expresión idiomática, redactada de formas ligeramente diferentes, en las que un cuantificador absoluto se combina con un imperativo [por ejemplo, «no [nunca] X», «[Usted debe] siempre Y», «[uno debe] nunca Z»] para formar declaraciones destinadas a ser utilizadas como reglas o pautas generales, especialmente cuando se les da a los nuevos en un tema, en lugar de ser como verdades absolutas, el no obstante la forma aparente de esas declaraciones.
Cuando comience a aprender un nuevo tema, y a menos que comprenda bien por qué podría necesitar hacer otra cosa, es una buena idea simplemente seguir las reglas generales aceptadas sin excepción, a menos que esté bajo la guía de alguien más experimentado. que tu mismo Con el aumento de la habilidad y la experiencia, podrá determinar cuándo y si se aplica una regla en una situación particular. Una vez que alcance un nivel significativo de experiencia, es probable que entienda el razonamiento detrás de la regla general en primer lugar, y en ese punto puede comenzar a usar su juicio sobre si y en qué nivel se aplican las razones detrás de la regla. esa situación, y también en cuanto a si existen preocupaciones primordiales.
Y es entonces cuando un experto, quizás, podría optar por hacer cosas en violación de "Las Reglas". Pero eso no los haría menos "Las Reglas".
Y, por lo tanto, con el tema en cuestión: en mi opinión, solo porque un experto pueda violar esta regla sin ser completamente golpeado, no veo ninguna forma de justificar decirle a un principiante que "a veces" es Está bien analizar la
ls
salida, porque: no lo es . O, al menos, ciertamente no es correcto que un principiante lo haga.Siempre pones tus peones en el centro; en la apertura de una pieza, un movimiento; castillo en la primera oportunidad; caballeros ante obispos; un caballero en el borde es sombrío; ¡y siempre asegúrese de poder ver su cálculo hasta el final! (Vaya, perdón, cansarse, eso es para el StackExchange de ajedrez).
¿Reglas que se deben romper?
Al leer un artículo sobre un tema dirigido a principiantes, o que pueda ser leído por ellos, a menudo verá cosas como esta:
Si bien estas afirmaciones ciertamente parecen indicar reglas absolutas y atemporales, no lo son; en cambio, esta es una forma de establecer reglas generales [también conocidas como "pautas", "reglas generales", "lo básico", etc.] que es al menos una forma apropiada de enunciarlas para los principiantes que podrían estar leyendo esos artículos. Sin embargo, solo porque se expresan como absolutos, las reglas ciertamente no vinculan a profesionales y expertos [quienes probablemente fueron los que resumieron tales reglas en primer lugar, como una forma de registrar y transmitir el conocimiento adquirido mientras se enfrentaban a recurrentes problemas en su oficio particular.]
Esas reglas ciertamente no van a revelar cómo un experto trataría un problema complejo o matizado, en el cual, digamos, esas reglas entran en conflicto entre sí; o en el que las preocupaciones que llevaron a la regla en primer lugar simplemente no se aplican. Los expertos no tienen miedo (¡o no deberían tener miedo de hacerlo!) Simplemente romper las reglas que saben que no tienen sentido en una situación particular. Los expertos están constantemente tratando de equilibrar varios riesgos y preocupaciones en su oficio, y con frecuencia deben usar su criterio para elegir romper ese tipo de reglas, tener que equilibrar varios factores y no poder confiar en una tabla de reglas a seguir. Tomemos
Goto
como ejemplo: ha habido un largo y recurrente debate sobre si son perjudiciales. (Sí, nunca uses gotos.; D)Una propuesta modal
Una característica extraña, al menos en inglés, y me imagino en muchos otros idiomas, de las reglas generales, es que se expresan en la misma forma que una propuesta modal, sin embargo, los expertos en un campo están dispuestos a dar una regla general para un situación, todo el tiempo sabiendo que romperán la regla cuando sea apropiado. Claramente, por lo tanto, estas declaraciones no están destinadas a ser equivalentes a las mismas declaraciones en lógica modal.
Es por eso que digo que simplemente deben ser idiomáticos. En lugar de ser realmente una situación de "nunca" o "siempre", estas reglas generalmente sirven para codificar pautas generales que tienden a ser apropiadas en una amplia gama de situaciones y que, cuando los principiantes las siguen ciegamente, es probable que resulten en mejores resultados que el principiante que elige ir en contra de ellos sin una buena razón. A veces codifican reglas que simplemente conducen a resultados deficientes en lugar de las fallas directas que acompañan a las elecciones incorrectas cuando van en contra de las reglas.
Entonces, las reglas generales no son las proposiciones modales absolutas que parecen estar en la superficie, sino que son una forma abreviada de dar la regla con un estándar estándar implícito, algo como lo siguiente:
donde, por supuesto, podría sustituir "nunca analizar la
ls
salida" en lugar de $ {REGLA}. :)¡Oh si! ¿Qué pasa con la
ls
salida de análisis ?Bueno, dado todo eso ... creo que está bastante claro que esta regla es buena. En primer lugar, la verdadera regla debe entenderse como idiomática, como se explicó anteriormente ...
Pero además, no es solo que tengas que ser muy bueno con las secuencias de comandos de shell para saber si se puede romper, en algún caso en particular. ¡También es que se necesita tanta habilidad para decir que te equivocaste cuando intentas romperlo en las pruebas! Y digo con confianza que una gran mayoría de la audiencia probable de tales artículos (dando consejos como «¡No analice la salida de
ls
!») No puede hacer esas cosas , y aquellos que tienen tal habilidad probablemente se darán cuenta de que ellos se dan cuenta solos e ignoran la regla de todos modosPero ... solo mira esta pregunta, y cómo incluso las personas que probablemente tienen la habilidad pensaron que era una mala decisión hacerlo; ¡y cuánto esfuerzo el autor de la pregunta gastó para llegar al punto del mejor ejemplo actual! Le garantizo que en un problema tan difícil, ¡el 99% de las personas se equivocarían y con resultados potencialmente muy malos! Incluso si el método que se decide resulta ser bueno; hasta que (u otra)
ls
idea de análisis sea adoptada por el personal de TI / desarrollador en su conjunto, resista muchas pruebas (especialmente la prueba del tiempo) y, finalmente, logre graduarse a un estado de 'técnica común', es probable que Mucha gente podría intentarlo y equivocarse ... con consecuencias desastrosas.Por lo tanto, voy a reiterar una vez más .... que, especialmente en este caso , que es por eso que " no analizar
ls
la salida!" es decididamente la forma correcta de expresarlo.[ACTUALIZACIÓN 2014-05-18: razonamiento aclarado para la respuesta (arriba) para responder a un comentario de OP; la siguiente adición es en respuesta a las adiciones del OP a la pregunta de ayer]
[ACTUALIZACIÓN 2014-11-10: encabezados agregados y contenido reorganizado / refactorizado; y también: reformatear, volver a redactar, aclarar y um ... "conciso" ... pretendía que esto fuera simplemente una limpieza, aunque se convirtió en un poco de un reproceso. Lo había dejado en un estado lamentable, así que traté principalmente de darle un poco de orden. sentí que era importante dejar en gran parte intacta la primera sección; entonces solo dos cambios menores allí, redundantes 'pero' eliminados, y 'eso' enfatizado.]
† Originalmente pretendía esto únicamente como una aclaración sobre mi original; pero decidió otras adiciones tras la reflexión
‡ consulte https://unix.stackexchange.com/tour para obtener instrucciones sobre publicaciones
fuente
ls
!' es un consejo correcto: 1. demuestre (para su satisfacción) que cada caso de uso en el que se puede analizar lals
salida tiene otra solución disponible, superior de alguna manera, sin hacerlo. 2. demuestre que, en los casos citados, la declaración no es literal.ls
es una utilidad informática: puede analizar la salida de la computadora.¿Es posible analizar la salida de
ls
en ciertos casos? Seguro. La idea de extraer una lista de números de inodo de un directorio es un buen ejemplo: si sabe que su implementación esls
compatible-q
y, por lo tanto, cada archivo producirá exactamente una línea de salida, y todo lo que necesita son los números de inodo, analizándolosls -Rai1q
La salida es sin duda una posible solución. Por supuesto, si el autor no hubiera visto consejos como "Nunca analizar el resultado de ls" antes, probablemente no pensaría en nombres de archivo con nuevas líneas en ellos, y probablemente dejaría la 'q' como resultado, y el el código se rompería sutilmente en ese caso límite, por lo que, incluso en los casos en que el resultado del análisisls
es razonable, este consejo sigue siendo útil.El punto más amplio es que, cuando un novato que shell scripting trata de tener una figura de la escritura a cabo (por ejemplo) lo que es el archivo más grande de un directorio, o lo que es el archivo modificado más recientemente en un directorio, su primer instinto es analizar
ls
's salida: comprensible, porquels
es uno de los primeros comandos que aprende un novato.Desafortunadamente, ese instinto está mal, y ese enfoque está roto. Aún más desafortunadamente, está sutilmente roto: funcionará la mayor parte del tiempo, pero fallará en casos extremos que tal vez podrían ser explotados por alguien con conocimiento del código.
El novato podría pensar
ls -s | sort -n | tail -n 1 | awk '{print $2}'
en una forma de obtener el archivo más grande en un directorio. Y funciona, hasta que tenga un archivo con un espacio en el nombre.OK, ¿qué tal
ls -s | sort -n | tail -n 1 | sed 's/[^ ]* *[0-9]* *//'
? Funciona bien hasta que tenga un archivo con una nueva línea en el nombre.No añadiendo
-q
als
's argumentos ayuda cuando hay una nueva línea en el nombre del archivo? Puede parecer así, hasta que tenga 2 archivos diferentes que contengan un carácter no imprimible en el mismo lugar en el nombre del archivo, y luegols
la salida no le permite distinguir cuál de ellos era el más grande. Peor aún, para expandir el "?", Probablemente recurra a su caparazón,eval
lo que causará problemas si golpea un archivo llamado, por ejemplo,¿
--quoting-style=shell
Ayuda (si tuls
incluso lo soporta)? No, todavía se muestra? para caracteres no imprimibles, por lo que aún es ambiguo cuál de las múltiples coincidencias fue la más grande.--quoting-style=literal
? No, lo mismo.--quoting-style=locale
o--quoting-style=c
podría ayudar si solo necesita imprimir el nombre del archivo más grande sin ambigüedades, pero probablemente no si necesita hacer algo con el archivo después; sería un montón de código para deshacer la cita y volver al nombre de archivo real que puedes pasar a, por ejemplo, gzip.Y al final de todo ese trabajo, incluso si lo que tiene es seguro y correcto para todos los nombres de archivo posibles, es ilegible e imposible de mantener, y podría haberse hecho de manera mucho más fácil, segura y legible en Python, Perl o Ruby.
O incluso usando otras herramientas de shell: desde la parte superior de mi cabeza, creo que esto debería hacer el truco:
Y debería ser al menos tan portátil como
--quoting-style
es.fuente