Это возможно, если CONFIG_BLOCK
не определено, поскольку init / do_mounts.c
содержится в mount_root
, который запускается после сбоя ядра / init
в initramfs следующее:
#ifdef CONFIG_BLOCK
{
int err = create_dev("/dev/root", ROOT_DEV);
if (err < 0)
pr_emerg("Failed to create /dev/root: %d\n", err);
mount_block_root("/dev/root", root_mountflags);
}
#endif
В этом случае mount_root
завершается успешно, ничего не сделав, и ядро продолжает рассматривать initramf как надлежащий корневой файловый сервер.
К сожалению, отключение CONFIG_BLOCK
в большинстве случаев нецелесообразно. Что заставило меня поверить, что это должно сработать, так это то, что в патче для конкретной платы разработки, с которой я работаю, условие было заменено на:
#if defined(CONFIG_BLOCK) && !defined(CONFIG_INITRAMFS_SOURCE)
Было бы неплохо добавить поддержку root = initramfs
, который заставляет mount_root
возвращаться без каких-либо действий, и это должен быть тривиальный однострочный патч. Однако я понятия не имею, будет ли это приемлемо для апстрима.
Debajo de uno está el que probé
filnames.txt==> Contiene todos los nombres de archivo
for j in `cat filenames.txt`; do sed "s/,/NA/g" $j >newfiles_$i;i=$(($i + 1)); done
Supongo que sus archivos CSV no tienen estrictamente comillas con comas y que no contienen campos con saltos de línea.
Esto cambiará los campos vacíos o campos que contienen solo espacios aNA
:
awk 'BEGIN { FS=OFS="," } { for (i=1;i<=NF;++i) if ($i ~ /^ *$/) $i = "NA"; print }'
Para cada campo separado por comas -en cada línea de entrada, probamos si coincide con la expresión regular ^ *$
. Si es así, el campo se reemplaza por la cadena NA
. Las variables FS
y OFS
en el bloque BEGIN
son los separadores de campo de entrada y salida, respectivamente. NF
es el número de campos que awk
detecta en la línea de entrada actual y si i
es un número entero, $i
será el campo correspondiente a ese número entero, contando desde uno.
Su línea de ejemplo,
SMVV, 2015-01-01 00:00,50065,780,7,1000,-2,18,,,1000
se convertiría en
SMVV, 2015-01-01 00:00,50065,780,7,1000,-2,18,NA,NA,1000
Ahora, para ejecutar esto en todos sus archivos, asumo que todos están en un directorio llamado dir
y que los nombres de los archivos coinciden con el patrón SMVV50065*.csv
.
Pasar por encima de estos archivos es una cuestión de
for name in dir/SMVV50065*.csv; do
test -f "$name" || continue
# construct new name and call awk here
done
Probamos con test -f
si el $name
es realmente un archivo normal y omitimos el resto de la iteración si no lo es. No sería si el patrón coincide con ningún nombre de directorio, o si el patrón no coincide con nada (, en cuyo caso se dejará sin expandir ).
Para construir nuevos nombres de archivo en el patrón que sugiere,podemos mantener una variable de contador que se incrementa en cada iteración, desde una en adelante, y llamar printf
con una cadena de formato que da el nombre del archivo de salida usando esta variable:
i=1
for name in dir/SMVV50065*.csv; do
test -f "$name" || continue
newname=$( printf 'newfile%02d.csv' "$i" )
i=$(( i + 1 ))
# call awk here
done
El %02d
en el formato printf
nos da un entero de 2 -dígitos cero -de $i
.
Ahora solo es cuestión de llamar awk
al nombre de archivo anterior y escribir el resultado en el nuevo. Escribiremos el resultado en archivos en el directorio result
, solo para mantenerlos separados de los archivos originales.
#!/bin/sh
mkdir -p result
i=1
for name in dir/SMVV50065*.csv; do
test -f "$name" || continue
newname=$( printf 'newfile%02d.csv' "$i" )
i=$(( i + 1 ))
awk 'BEGIN { FS=OFS="," } { for (i=1;i<=NF;++i) if ($i ~ /^ *$/) $i = "NA"; print }' "$name" >result/"$newname"
done
Lo único que he hecho aquí es asegurarme de que el directorio result
realmente existe con mkdir -p result
al principio. También agregué una línea#!
-en la parte superior para decir que este es un script sh
.
Y de nuevo, con un poco de diagnóstico y parametrización añadidos:
#!/bin/sh
indir=dir
outdir=result
mkdir -p "$outdir"
i=1
for name in "$indir"/SMVV50065*.csv; do
if [ ! -f "$name" ]; then
printf 'Not a regular file: "%s"\n' "$name" >&2
continue
fi
newname=$( printf '%s/newfile%02d.csv' "$outdir" "$i" )
i=$(( i + 1 ))
printf 'Processing "%s" into "%s"...\n' "$name" "$newname" >&2
awk 'BEGIN { FS=OFS="," } { for (i=1;i<=NF;++i) if ($i ~ /^ *$/) $i = "NA"; print }' "$name" >"$newname"
done
Obviamente, podrías poner tu sed
comando aquí en lugar de mi awk
cosita, si quieres.
Pregunta en comentarios:
Lo anterior parece difícil, ¿por qué no podemos simplemente hacer
foreach file (ls SMVV50065-2015-0[1-7].csv)
sed 's/,/NA/g' > newfile0[1-7].csv
end
Responder:
Primero tenemos que empezar usando la sintaxis correcta. Esto se parece un poco a la sintaxis del shell csh
, pero dado que no se mencionó ningún shell en particular en la pregunta y dado quesh
-los shells similares se usan más comúnmente, y ya que personalmente tengo muy poca experiencia con csh
y tcsh
, voy a convertirlo en sintaxis sh
.
El bucle en sh
shells es for
en lugar de foreach
y usamos in
y do
en lugar del paréntesis. También sugiere usar ls
para el ciclo, pero ls
es estrictamente un comando interactivo cuyo resultado es solo para mirar(ver " Por qué *no *analizar `ls `? " ). Es suficiente con un patrón de globbing de nombre de archivo para generar una lista de nombres de archivo para recorrer.
Así que usemos su bucle con la sintaxis correcta:
for file in SMVV50065-2015-0[1-7].csv; do
sed 's/,/NA/g' > newfile0[1-7].csv
done
El siguiente problema con el bucle aquí es que no sabemos si $file
será un valor útil. Si el patrón SMVV50065-2015-0[1-7].csv
coincide con un nombre de directorio o si no coincide con nada, entonces no deberíamos usar $file
, así que probemos eso:
for file in SMVV50065-2015-0[1-7].csv; do
test -f "$file" || continue
sed 's/,/NA/g' > newfile0[1-7].csv
done
Ahora para la invocación sed
:Deberá pasar el nombre de archivo $file
a sed
para que tenga algo en lo que trabajar:
for file in SMVV50065-2015-0[1-7].csv; do
test -f "$file" || continue
sed 's/,/NA/g' "$file" > newfile0[1-7].csv
done
El siguiente problema es que en realidad no puede redirigir la salida de sed
a un patrón de englobamiento de nombre de archivo como newfile0[1-7].csv
. El shell expandirá un patrón global a todos los nombres que coincidan con ese patrón, o permanecerá sin expandir si no coincide con nada.
Suponiendo que no tiene ningún archivo en el directorio actual que coincida con el patrón newfile0[1-7].csv
. Luego, el ciclo creará un archivo llamado newfile0[1-7].csv
, y este relleno se sobrescribirá en cada iteración del ciclo.
Es por eso que introduje mi variable i
, para poder construir un nuevo nombre de archivo en cada iteración:
i=1
for file in SMVV50065-2015-0[1-7].csv; do
test -f "$file" || continue
sed 's/,/NA/g' "$file" >"newfile0$i.csv"
i=$(( i + 1 ))
done
Supuse que puede tener mucho más que solo siete archivos para procesar, y es por eso que pasé por ese pequeño problema adicional para generar el nombre del archivo de salida usando printf
, para asegurarme de que obtuviéramos un nombre de archivo con un cero -número rellenado en él.
El ciclo anterior puede funcionar para usted tal como está, pero si lo reformulo un poco (asigne el nuevo nombre de archivo a una variable y utilícelo consed
):
i=1
for file in SMVV50065-2015-0[1-7].csv; do
test -f "$file" || continue
newname="newfile0$i.csv"
i=$(( i + 1 ))
sed 's/,/NA/g' "$file" >"$newfile"
done
¿Ves? Estamos más o menos de vuelta en mi solución (sin las campanas y silbidos adicionales de mi última variación ). La única diferencia radical es que aquí asume que todos los archivos estarán disponibles en el directorio actual y que los archivos de salida deben crearse junto con los archivos originales.