Necesito ejecutar periódicamente un comando que garantice que algunos archivos de texto se mantengan en modo Linux. Desafortunadamente, dos2unix
siempre modifica el archivo, lo que ensuciaría las marcas de tiempo del archivo y la carpeta y causaría escrituras innecesarias.
El guión que escribo está en Bash, por lo que preferiría respuestas basadas en Bash.
bash
text-processing
newlines
Adam Ryczkowski
fuente
fuente
test
pormyfile.txt
dos veces en su ejemplo para evitar confusiones con/usr/bin/test
.-s
bandera para ver la salida. De las páginas man:-s, --quiet, --silent suppress all normal output
Si el objetivo es simplemente evitar afectar la marca de tiempo,
dos2unix
tiene una opción-k
u--keepdate
opción que mantendrá la marca de tiempo igual. Todavía tendrá que escribir para crear el archivo temporal y cambiarle el nombre, pero sus marcas de tiempo no se verán afectadas.Si alguna modificación del archivo es inaceptable, puede usar la siguiente solución de esta respuesta .
fuente
find ... -exec file ... | grep CRLF
para un archivo con terminaciones de línea de DOS (es decir, bytes 0D 0A) "obtendrá algo como:./1/dos1.txt: ASCII text, with CRLF line terminators
Como puede ver, esto contiene la cadena CRLF real y, por lo tanto, segrep
busca buscando la cadena simple CRLF.Puede intentar el
grep
código CRLF, octal:o hexadecimal:
fuente
grep
uso porque me permite enumerar fácilmente todos esos archivos en el directoriogrep -lU $'\x0D' *
y pasarle la salidaxargs
.Desde la versión
7.1
dos2unix tiene una-i
,--info
opción para obtener información sobre los saltos de línea. Puede usar dos2unix para probar qué archivos necesitan conversión.Ejemplo:
fuente
Primer método (
grep
):Cuente las líneas que contienen un retorno de carro:
Cuente las líneas que terminan con un retorno de carro:
Estos serán típicamente equivalentes; un retorno de carro en el interior de una línea (es decir, no al final) es raro.
Más eficiente:
Esto es mas eficiente
grep -c
necesita leer todo el archivo, para contar todas las apariciones del patrón, mientras quegrep -q
puede salir al ver la primera aparición del patrón.Notas:
-U
opción (es decir, usar-cU
o-qU
), porque GNUgrep
adivina si el archivo es un archivo de texto. Si cree que el archivo es texto, ignora los retornos de carro al final de las líneas, en un intento de hacer que$
las expresiones regulares funcionen "correctamente", ¡incluso si la expresión regular lo es\r$
! La especificación-U
(o--binary
) anula esta conjetura, logrep
que hace que los archivos se traten como binarios y pasen los datos al mecanismo de coincidencia textualmente, con terminaciones CR intactas.grep … $'\r\n' myfile.txt
, porque segrep
trata\n
como un delimitador de patrón. Así comogrep -E 'foo|'
busca líneas que contienenfoo
o una cadena nula,grep $'\r\n'
busca líneas que contienen\r
o una cadena nula, y cada línea coincide con una cadena nula.Segundo método (
file
):porque
file
informa algo como:Variante más segura:
dónde
file -b
genera solo el tipo de archivo y no el nombre del archivo. Sin esto, un archivo cuyo nombre incluyera los caracteresCRLF
provocaría un falso positivo.file - < filename
funciona incluso sifilename
comienza con-
. Ver Script Bash: verifica si un archivo es un archivo de texto .Tenga en cuenta que la comprobación de la salida
file
puede no funcionar en una configuración regional que no esté en inglés.fuente
"$(echo -e '\r')"
por uno mucho más simple$'\r'
, aunque personalmente lo usaría$'\r\n'
para reducir la cantidad de falsos positivos.grep $'\r\n'
parece coincidir con todos los archivos en mi sistema ...grep -U $'\r$'
, para evitargrep
tratar de adivinar las terminaciones de línea.-q
simplemente establecer el código de retorno si se encuentra una coincidencia, en lugar de lo-c
cual requiere una verificación adicional. Personalmente, me gusta su segunda solución, aunque depende en gran medida de los caprichosfile
y podría no funcionar en un entorno no inglés.Utilizar
cat -A
Ahora, si este archivo se hizo en sistemas * NIX, se mostrará
Pero si este archivo se hizo en Windows, se mostrará
^M
representaCR
y$
representaLF
. Observe que Windows no guardó la última línea conCRLF
Esto tampoco cambia el contenido del archivo.
fuente
-A
para el gato. Un consejo, aunque sería utilizarcat -A file | less
si el archivo es demasiado grande. Estoy seguro de que no es raro tener que verificar las terminaciones de archivos para un archivo particularmente largo. (Presioneq
para dejar menos)una función bash para ti:
Entonces puedes hacer cosas como
fuente
isDosFile()
en su ejemplo:streamFile() { sed 's/\r$//' "$1" ; }
.Si un archivo tiene terminaciones de línea CR-LF estilo DOS / Windows, entonces si lo mira usando una herramienta basada en Unix, verá caracteres CR ('\ r') al final de cada línea.
Este comando:
se imprimirá
filename
si el archivo contiene una o más líneas con terminaciones de línea estilo Windows, y no imprimirá nada si no lo tiene. Excepto que^M
tiene que ser un carácter de retorno de carro literal, típicamente ingresado en la terminal escribiendo Ctrl+ Vseguido de Enter (o Ctrl+ Vy luego Ctrl+ M). El shell bash le permite escribir un retorno de carro literal como$'\r'
( documentado aquí ), para que pueda escribir:Otros proyectiles pueden proporcionar una característica similar.
Puede usar otra herramienta en su lugar:
Esto saldrá con un estado de
1
(configuración$?
a1
) si el archivo contiene cualquier final de línea al estilo de Windows, y con un estado de0
si no lo hace, lo que lo hace útil en unaif
declaración de shell (tenga en cuenta la falta de[
corchetes]
):Un archivo puede contener una mezcla de terminaciones de línea estilo Unix y estilo Windows. Supongo aquí que desea detectar archivos que tengan cualquier final de línea estilo Windows.
fuente
$'\r'
, como se menciona en otras respuestas a esta pregunta.Uso
file
:fuente
he estado usando
que parece funcionar Encuentro la salida un poco más fácil de leer que
También es útil si no puede instalar
dos2unix
por alguna razón.fuente