Tengo un archivo csv muy grande. ¿Cómo eliminarías el último ,
con sed (o similar)?
...
[11911,0,"BUILDER","2014-10-15","BUILDER",0,0],
[11912,0,"BUILDER","2014-10-15","BUILDER",0,0],
[11913,0,"BUILDER","2014-10-15","BUILDER",0,0],
]
Salida deseada
...
[11911,0,"BUILDER","2014-10-15","BUILDER",0,0],
[11912,0,"BUILDER","2014-10-15","BUILDER",0,0],
[11913,0,"BUILDER","2014-10-15","BUILDER",0,0]
]
El siguiente comando sed eliminará la última aparición por línea, pero quiero por archivo.
sed -e 's/,$//' foo.csv
Esto tampoco funciona
sed '$s/,//' foo.csv
Respuesta1
Usandoawk
Si la coma siempre está al final de la penúltima línea:
$ awk 'NR>2{print a;} {a=b; b=$0} END{sub(/,$/, "", a); print a;print b;}' input
[11911,0,"BUILDER","2014-10-15","BUILDER",0,0],
[11912,0,"BUILDER","2014-10-15","BUILDER",0,0],
[11913,0,"BUILDER","2014-10-15","BUILDER",0,0]
]
Usando awk
ybash
$ awk -v "line=$(($(wc -l <input)-1))" 'NR==line{sub(/,$/, "")} 1' input
[11911,0,"BUILDER","2014-10-15","BUILDER",0,0],
[11912,0,"BUILDER","2014-10-15","BUILDER",0,0],
[11913,0,"BUILDER","2014-10-15","BUILDER",0,0]
]
Usandosed
$ sed 'x;${s/,$//;p;x;};1d' input
[11911,0,"BUILDER","2014-10-15","BUILDER",0,0],
[11912,0,"BUILDER","2014-10-15","BUILDER",0,0],
[11913,0,"BUILDER","2014-10-15","BUILDER",0,0]
]
Para OSX y otras plataformas BSD, intente:
sed -e x -e '$ {s/,$//;p;x;}' -e 1d input
Usandobash
while IFS= read -r line
do
[ "$a" ] && printf "%s\n" "$a"
a=$b
b=$line
done <input
printf "%s\n" "${a%,}"
printf "%s\n" "$b"
Respuesta2
Simplemente puede probar el siguiente comando de una sola línea de Perl.
perl -00pe 's/,(?!.*,)//s' file
Explicación:
,
Coincide con una coma.(?!.*,)
La búsqueda anticipada negativa afirma que no habría una coma después de esa coma coincidente. Entonces coincidiría con la última coma.s
Y lo más importante ess
el modificador DOTALL, que hace que el punto coincida incluso con los caracteres de nueva línea.
Respuesta3
lcomma() { sed '
$x;$G;/\(.*\),/!H;//!{$!d
}; $!x;$s//\1/;s/^\n//'
}
Eso debería eliminar solo la última aparición de a ,
en cualquier archivo de entrada, y aún imprimirá aquellos en los que a ,
no aparece. Básicamente, almacena secuencias de líneas que no contienen una coma.
Cuando encuentra una coma, intercambia el búfer de línea actual con el búfer de retención y de esa manera imprime simultáneamente todas las líneas que ocurrieron desde la última coma.ylibera su buffer de retención.
Estaba revisando mi archivo de historial y encontré esto:
lmatch(){ set "USAGE:\
lmatch /BRE [-(((s|-sub) BRE)|(r|-ref)) REPL [-(f|-flag) FLAG]*]*
" "${1%"${1#?}"}" "$@"
eval "${ZSH_VERSION:+emulate sh}"; eval '
sed " 1x; \\$3$2!{1!H;\$!d
}; \\$3$2{x;1!p;\$!d;x
}; \\$3$2!x;\\$3$2!b'"
$( unset h;i=3 p=:-:shfr e='\033[' m=$(($#+1)) f=OPTERR
[ -t 2 ] && f=$e\2K$e'1;41;17m}\r${h-'$f$e\0m
f='\${$m?"\"${h-'$f':\t\${$i$e\n}\$1\""}\\c' e=} _o=
o(){ IFS=\ ;getopts $p a "$1" &&
[ -n "${a#[?:]}" ] &&
o=${a#-}${OPTARG-${1#-?}} ||
! eval "o=$f;o=\${o%%*\{$m\}*}"
}; a(){ case ${a#[!-]}$o in (?|-*) a=;;esac; o=
set $* "${3-$2$}{$((i+=!${#a}))${a:+#-?}}"\
${3+$2 "{$((i+=1))$e"} $2
IFS=$; _o=${_o%"${3+$_o} "*}$*\
}; while eval "o \"\${$((i+=(OPTIND=1)))}\""
do case ${o#[!$a]} in
(s*|ub) a s 2 '' ;;
(r*|ef) a s 2 ;;
(f*|lag) a ;;
(h*|elp) h= o; break ;;
esac; done; set -f; printf "\t%b\n\t" $o $_o
)\"";}
En realidad es bastante bueno. Sí, usa eval
, pero nunca le pasa nada más allá de una referencia numérica a sus argumentos. Crea sed
scripts arbitrarios para manejar un último partido. Te mostrare:
printf "%d\" %d' %d\" %d'\n" $(seq 5 5 200) |
tee /dev/fd/2 |
lmatch d^.0 \ #all re's delimit w/ d now
-r '&&&&' \ #-r or --ref like: '...s//$ref/...'
--sub \' sq \ #-s or --sub like: '...s/$arg1/$arg2/...'
--flag 4 \ #-f or --flag appended to last -r or -s
-s\" \\dq \ #short opts can be '-s $arg1 $arg2' or '-r$arg1'
-fg #tacked on so: '...s/"/dq/g...'
Eso imprime lo siguiente en stderr. Esta es una copia de lmatch
la entrada de:
5" 10' 15" 20'
25" 30' 35" 40'
45" 50' 55" 60'
65" 70' 75" 80'
85" 90' 95" 100'
105" 110' 115" 120'
125" 130' 135" 140'
145" 150' 155" 160'
165" 170' 175" 180'
185" 190' 195" 200'
El subnivel ed de la función eval
itera todos sus argumentos una vez. A medida que los recorre, itera un contador de manera adecuada según el contexto de cada cambio y omite esa cantidad de argumentos para la siguiente iteración. A partir de entonces hace una de varias cosas por argumento:
- Para cada opción, el analizador de opciones
$a
agrega$o
.$a
se asigna en función de cuyo valor$i
se incrementa en el recuento de argumentos para cada argumento procesado.$a
se le asigna uno de los dos valores siguientes:a=$((i+=1))
- esto se asigna si una opción corta no tiene su argumento adjunto o si la opción era larga.a=$i#-?
- esto se asigna si la opción es corta yhacetenga su argumento adjunto.a=\${$a}${1:+$d\${$(($1))\}}
- Independientemente de la asignación inicial,$a
el valor de 's siempre está entre llaves y, en algunos-s
casos, a veces$i
se incrementa en uno más y además se agrega un campo delimitado.
El resultado es que eval
nunca se pasa una cadena que contenga incógnitas. Se hace referencia a cada uno de los argumentos de la línea de comandos por su número de argumento numérico, incluso el delimitador que se extrae del primer carácter del primer argumento y es la única vez que debe usar cualquier carácter sin escape. Básicamente, la función es un generador de macros: nunca interpreta los valores de los argumentos de ninguna manera especial porque sed
puede(y lo hará, por supuesto)manejar eso fácilmente cuando analiza el script. En cambio, simplemente organiza sensatamente sus argumentos en un script viable.
Aquí hay algunos resultados de depuración de la función en funcionamiento:
... sed " 1x;\\$2$1!{1!H;\$!d
}; \\$2$1{x;1!p;\$!d;x
}; \\$2$1!x;\\$2$1!b
s$1$1${4}$1
s$1${6}$1${7}$1${9}
s$1${10#-?}$1${11}$1${12#-?}
"
++ sed ' 1x;\d^.0d!{1!H;$!d
}; \d^.0d{x;1!p;$!d;x
}; \d^.0d!x;\d^.0d!b
sdd&&&&d
sd'\''dsqd4
sd"d\dqdg
'
Y, por lo tanto, lmatch
se puede utilizar para aplicar fácilmente expresiones regulares a los datos posteriores a la última coincidencia en un archivo. El resultado del comando que ejecuté arriba es:
5" 10' 15" 20'
25" 30' 35" 40'
45" 50' 55" 60'
65" 70' 75" 80'
85" 90' 95" 100'
101010105dq 110' 115dq 120'
125dq 130' 135dq 140sq
145dq 150' 155dq 160'
165dq 170' 175dq 180'
185dq 190' 195dq 200'
...que, dado el subconjunto de la entrada del archivo que sigue a la última vez /^.0/
que coincide, aplica las siguientes sustituciones:
sdd&&&&d
- se reemplaza$match
consigo mismo 4 veces.sd'dsqd4
- la cuarta comilla simple que sigue al comienzo de la línea desde el último partido.sd"d\dqd2
- lo mismo, pero para comillas dobles y globalmente.
Y así, para demostrar cómo se podría utilizar lmatch
para eliminar la última coma de un archivo:
printf "%d, %d %d, %d\n" $(seq 5 5 100) |
lmatch '/\(.*\),' -r\\1
PRODUCCIÓN:
5, 10 15, 20
25, 30 35, 40
45, 50 55, 60
65, 70 75, 80
85, 90 95 100
Respuesta4
verhttps://stackoverflow.com/questions/12390134/remove-comma-from-last-line
Esto funcionó para mí:
$cat input.txt
{"name": "secondary_ua","type":"STRING"},
{"name": "request_ip","type":"STRING"},
{"name": "cb","type":"STRING"},
$ sed '$s/,$//' < input.txt >output.txt
$cat output.txt
{"name": "secondary_ua","type":"STRING"},
{"name": "request_ip","type":"STRING"},
{"name": "cb","type":"STRING"}
Mi mejor manera es eliminar la última línea y, después de eliminar la coma, agregar el carácter ] nuevamente.