Tengo un destino que consume archivos CSV y el sexto campo contiene palabras, pero la longitud máxima de caracteres es 16. Si la longitud del campo supera los 16 caracteres, me gustaría duplicar la línea y dividirla sin dividir las palabras.
Archivo actual
"5","4","3","2","1","XYZ ABCD E"
"1","2","3","4","5","AB CDE F GHI JK LMNOP Q RS TUV W XYZ 12 3456 7890"
"9","8","7","6","5","LMN O PQ R"
Salida deseada
"5","4","3","2","1","XYZ ABCD E"
"1","2","3","4","5","AB CDE F GHI JK"
"1","2","3","4","5","LMNOP Q RS TUV W"
"1","2","3","4","5","XYZ 12 3456 7890"
"9","8","7","6","5","LMN O PQ R"
Respuesta1
Usando GNU Awk ( gawk
) para ejecutar fold
unGetline/Variable/Coproceso
gawk -F, '
BEGIN{
OFS=FS;
cmd="fold -sw 16";
}
# if total length (16 + 2 for quotes) is within limit, print as-is
length($NF) <= 18 {print; next}
# else
{
# trim the quotes, then fold
print substr($NF,2,length($NF)-2) |& cmd;
close(cmd,"to");
NF--;
while((cmd |& getline var) > 0){
# (optional) trim trailing whitespace
sub(/[ \t]+$/,"",var);
print $0, "\"" var "\"" ;
}
close(cmd,"from");
}
' file.csv
Elimina sub
los espacios en blanco finales de la fold
operación.
Tenga en cuenta que para obtener el resultado preciso que se muestra, sería necesario utilizar fold -sw17
para dividir en 16 caracteres más el espacio final (posteriormente eliminado). Sin embargo, al hacerlo se crea la posibilidad de exceder el límite de 16 caracteres en la última línea de la salida plegada.
Respuesta2
He creado un script awk bastante aburrido que conserva las comillas dobles. Aquí viene:
{
for ( i=0; i<= length($6); i+=16 )
{
if ( i+17 < length($6) )
{
if ( i == 0 )
printf ("%s,%s,%s,%s,%s,%s\"\n", $1, $2, $3, $4, $5, substr($6,i,16))
else
printf ("%s,%s,%s,%s,%s,\"%s\"\n", $1, $2, $3, $4, $5, substr($6,i+1,16))
}
else
{
if ( i == 0 )
printf ("%s,%s,%s,%s,%s,%s\n", $1, $2, $3, $4, $5, substr($6,i,16))
else
printf ("%s,%s,%s,%s,%s,\"%s\n", $1, $2, $3, $4, $5, substr($6,i+1,16))
}
}
}
La salida es:
$ awk -F, -f awks csvfields
"5","4","3","2","1","XYZ ABCD E"
"1","2","3","4","5","AB CDE F GHI JK"
"1","2","3","4","5"," LMNOP Q RS TUV "
"1","2","3","4","5","W XYZ 12 3456 78"
"1","2","3","4","5","90"
"9","8","7","6","5","LMN O PQ R"
$
El único problema es que si hay un espacio en el límite, se conserva a diferencia del ejemplo en el que se eliminó.
Respuesta3
Probé con el siguiente código y también funcionó bien.
k=16;for ((j=1;j<=50;j++)); do awk -v j="$j" -v k="$k" -F "," '{if(length($NF) > 16){print $1,$2,$3,$4,$5,substr($NF,j,k)}else {print $0}}' filename; j=$(($j+16)); done|sort | uniq
producción
"5","4","3","2","1","XYZ ABCD E"
"1","2","3","4","5","AB CDE F GHI JK"
"1","2","3","4","5","LMNOP Q RS TUV W"
"1","2","3","4","5","XYZ 12 3456 7890"
"9","8","7","6","5","LMN O PQ R"
Respuesta4
Un enfoque exclusivo de SHELL (probado en Bash y Ksh93). Sin embargo, me gusta el fold
enfoque ya que utiliza una herramienta existente.
# read from stdin, output to stdout
# Note no Shebang line at top so it made it easier for to try bash/ksh as interpreters
OIFS="$IFS"
IFS=,
while read f1 f2 f3 f4 f5 f6; do
f6=${f6#\"}
f6=${f6%\"} # strip DQs
if ((${#f6}<17)); then # no action
IFS="$OIFS"
echo "$f1,$f2,$f3,$f4,$f5,\"$f6\""
IFS=","
continue
else
IFS="$OIFS"
while ((${#f6}>17)); do
n6=${f6:0:16}
f6=${f6#$n6}
n6=${n6# }
n6=${n6% }
echo "$f1,$f2,$f3,$f4,$f5,\"$n6\""
done
echo "$f1,$f2,$f3,$f4,$f5,\"${f6# }\""
fi
IFS=","
done
IFS="$OIFS"
exit
Resultados:
"5","4","3","2","1","XYZ ABCD E"
"1","2","3","4","5","AB CDE F GHI JK"
"1","2","3","4","5","LMNOP Q RS TUV W"
"1","2","3","4","5","XYZ 12 3456 7890"
"9","8","7","6","5","LMN O PQ R"
Para solucionar el problema de la ruptura de palabras sin usar fold
o algo similar, el siguiente código debe reemplazar la línea comentada que se muestra a continuación en lo anterior. También reemplace la segunda echo
línea de comando con:
c6="$f6"
n6=""
while (((${#n6}+${#nw})<=16)); do
n6=$n6${c6%% *}\
n6=${n6# }
eval c6=\${c6\#${c6%% *} }
nw=${c6%% *}
done
#n6=${f6:0:16} ### replace by above
y reemplazar
echo "$f1,$f2,$f3,$f4,$f5,\"${f6# }\""
con
((${#f6}>0)) && echo "$f1,$f2,$f3,$f4,$f5,\"${f6# }\""
para evitar que se produzcan restos de campo nulo 6.
Se utilizó el siguiente archivo de prueba:
"5","4","3","2","1","XYZ ABCD E"
"1","2","3","4","5","AB CDE F GHI JK LMNOP Q RS TUV W XYZ 12 3456 7890"
"9","8","7","6","5","LMN O PQ R"
"1","2","3","4","5","A BB CCC DDD EEEE FFFFF GGGGGG HHHHHHH"
con resultados:
"5","4","3","2","1","XYZ ABCD E"
"1","2","3","4","5","AB CDE F GHI JK"
"1","2","3","4","5","LMNOP Q RS TUV W"
"1","2","3","4","5","XYZ 12 3456 7890"
"9","8","7","6","5","LMN O PQ R"
"1","2","3","4","5","A BB CCC DDD"
"1","2","3","4","5","EEEE FFFFF"
"1","2","3","4","5","GGGGGG HHHHHHH"
Sin embargo , el uso de las herramientas existentes fold
es mucho más fácil y sigue la filosofía UNIX: construir sobre herramientas simples existentes. Pero si le gusta la programación Shell, lo anterior es una forma de encontrar una solución. Si alguien necesita explicaciones del código, póngase en contacto conmigo.