Respuestas:
Para la cut(1)página del manual:
Use uno, y solo uno de -b, -c o -f. Cada LISTA está compuesta por un rango, o muchos rangos separados por comas. La entrada seleccionada se escribe en el mismo orden en que se lee y se escribe exactamente una vez.
Primero llega al campo 1, de modo que se imprime, seguido del campo 2.
Use en su awklugar:
awk '{ print $2 " " $1}' file.txt
FSes una opción, OFSes una variable. egawk -v OFS=";" -F"\t" '{print $2,$1}'
| sed 's/\r//' | antes de awk
awk '{print $4 "\t" $2 "\t" $6 "\t" $7}' file
También puede combinar cuty paste:
paste <(cut -f2 file.txt) <(cut -f1 file.txt)
a través de comentarios: es posible evitar bashisms y eliminar una instancia de corte haciendo:
paste file.txt file.txt | cut -f2,3
cutfunciona bien para columnas de longitud variable siempre que tenga un separador de columna único.
bashismos y eliminar una instancia de cuthaciendo: paste file.txt file.txt | cut -f2,3
usando solo el caparazón,
while read -r col1 col2
do
echo $col2 $col1
done <"file"
"$col2"y "$col1", podría haber metacaracteres de shell u otras travesuras en los datos.
Puedes usar Perl para eso:
perl -ane 'print "$F[1] $F[0]\n"' < file.txt
La ventaja de ejecutar perl es que (si conoce a Perl) puede hacer muchos más cálculos en F que reorganizar columnas.
perl -ae printfunciona catpara mí
Utilizando join:
join -t $'\t' -o 1.2,1.1 file.txt file.txt
Notas:
-t $'\t'En GNU join el más intuitivo -t '\t' y sin la $falla, ( coreutils v8.28 y anteriores?); Probablemente sea un error que una solución alternativa $debería ser necesaria. Ver: unix join separator char .
joinnecesita dos nombres de archivo, aunque solo se esté trabajando en un archivo. Usar el mismo nombre dos veces engaña joinpara realizar la acción deseada.
Para sistemas con bajos recursos joinofrece una huella más pequeña que algunas de las herramientas utilizadas en otras respuestas:
wc -c $(realpath `which cut join sed awk perl`) | head -n -1
43224 /usr/bin/cut
47320 /usr/bin/join
109840 /bin/sed
658072 /usr/bin/gawk
2093624 /usr/bin/perlAcabo de trabajar en algo muy similar, no soy un experto, pero pensé que compartiría los comandos que he usado. Tenía un csv de varias columnas del que solo necesitaba 4 columnas y luego necesitaba reordenarlas.
Mi archivo era pipe '|' delimitado pero eso se puede cambiar.
LC_ALL=C cut -d$'|' -f1,2,3,8,10 ./file/location.txt | sed -E "s/(.*)\|(.*)\|(.*)\|(.*)\|(.*)/\3\|\5\|\1\|\2\|\4/" > ./newcsv.csv
¡Es cierto que es realmente duro y listo, pero se puede ajustar para adaptarse!
Usando sed
Use sed con subexpresiones anidadas de expresiones regulares básicas para capturar y reordenar el contenido de la columna. Este enfoque es más adecuado cuando hay un número limitado de cortes para reordenar columnas, como en este caso.
La idea básica es rodear porciones interesantes del patrón de búsqueda con \(y \), que se puede reproducir en el patrón de reemplazo con \#where #representa la posición secuencial de la subexpresión en el patrón de búsqueda.
Por ejemplo:
$ echo "foo bar" | sed "s/\(foo\) \(bar\)/\2 \1/"
rendimientos:
bar foo
El texto fuera de una subexpresión se escanea pero no se retiene para reproducirlo en la cadena de reemplazo.
Aunque la pregunta no discutió columnas de ancho fijo, discutiremos aquí ya que esta es una medida digna de cualquier solución planteada. Para simplificar, supongamos que el archivo está delimitado por espacios, aunque la solución se puede ampliar para otros delimitadores.
Espacios colapsados
Para ilustrar el uso más simple, supongamos que se pueden contraer múltiples espacios en espacios individuales, y los valores de la segunda columna se terminan con EOL (y no con espacio).
Expediente:
bash-3.2$ cat f
Column1 Column2
str1 1
str2 2
str3 3
bash-3.2$ od -a f
0000000 C o l u m n 1 sp sp sp sp C o l u m
0000020 n 2 nl s t r 1 sp sp sp sp sp sp sp 1 nl
0000040 s t r 2 sp sp sp sp sp sp sp 2 nl s t r
0000060 3 sp sp sp sp sp sp sp 3 nl
0000072
Transformar:
bash-3.2$ sed "s/\([^ ]*\)[ ]*\([^ ]*\)[ ]*/\2 \1/" f
Column2 Column1
1 str1
2 str2
3 str3
bash-3.2$ sed "s/\([^ ]*\)[ ]*\([^ ]*\)[ ]*/\2 \1/" f | od -a
0000000 C o l u m n 2 sp C o l u m n 1 nl
0000020 1 sp s t r 1 nl 2 sp s t r 2 nl 3 sp
0000040 s t r 3 nl
0000045
Preservar anchos de columna
Extendamos ahora el método a un archivo con columnas de ancho constante, mientras permitimos que las columnas sean de diferentes anchos.
Expediente:
bash-3.2$ cat f2
Column1 Column2
str1 1
str2 2
str3 3
bash-3.2$ od -a f2
0000000 C o l u m n 1 sp sp sp sp C o l u m
0000020 n 2 nl s t r 1 sp sp sp sp sp sp sp 1 sp
0000040 sp sp sp sp sp nl s t r 2 sp sp sp sp sp sp
0000060 sp 2 sp sp sp sp sp sp nl s t r 3 sp sp sp
0000100 sp sp sp sp 3 sp sp sp sp sp sp nl
0000114
Transformar:
bash-3.2$ sed "s/\([^ ]*\)\([ ]*\) \([^ ]*\)\([ ]*\)/\3\4 \1\2/" f2
Column2 Column1
1 str1
2 str2
3 str3
bash-3.2$ sed "s/\([^ ]*\)\([ ]*\) \([^ ]*\)\([ ]*\)/\3\4 \1\2/" f2 | od -a
0000000 C o l u m n 2 sp C o l u m n 1 sp
0000020 sp sp nl 1 sp sp sp sp sp sp sp s t r 1 sp
0000040 sp sp sp sp sp nl 2 sp sp sp sp sp sp sp s t
0000060 r 2 sp sp sp sp sp sp nl 3 sp sp sp sp sp sp
0000100 sp s t r 3 sp sp sp sp sp sp nl
0000114
Por último, aunque el ejemplo de la pregunta no tiene cadenas de longitud desigual, esta expresión sed respalda este caso.
Expediente:
bash-3.2$ cat f3
Column1 Column2
str1 1
string2 2
str3 3
Transformar:
bash-3.2$ sed "s/\([^ ]*\)\([ ]*\) \([^ ]*\)\([ ]*\)/\3\4 \1\2/" f3
Column2 Column1
1 str1
2 string2
3 str3
bash-3.2$ sed "s/\([^ ]*\)\([ ]*\) \([^ ]*\)\([ ]*\)/\3\4 \1\2/" f3 | od -a
0000000 C o l u m n 2 sp C o l u m n 1 sp
0000020 sp sp nl 1 sp sp sp sp sp sp sp s t r 1 sp
0000040 sp sp sp sp sp nl 2 sp sp sp sp sp sp sp s t
0000060 r i n g 2 sp sp sp nl 3 sp sp sp sp sp sp
0000100 sp s t r 3 sp sp sp sp sp sp nl
0000114
Comparación con otros métodos de reordenamiento de columnas bajo shell
Sorprendentemente para una herramienta de manipulación de archivos, awk no es adecuado para cortar desde un campo hasta el final del registro. En sed esto se puede lograr utilizando expresiones regulares, por ejemplo, \(xxx.*$\)dónde xxxestá la expresión para que coincida con la columna.
Usar pegar y cortar subshells se vuelve complicado cuando se implementan scripts de shell. El código que funciona desde la línea de comandos no se analiza cuando se introduce dentro de un script de shell. Al menos esta fue mi experiencia (lo que me llevó a este enfoque).
Ampliando la respuesta de @Met, también usando Perl:
Si la entrada y la salida están delimitadas por TAB:
perl -F'\t' -lane 'print join "\t", @F[1, 0]' in_file
Si la entrada y la salida están delimitadas por espacios en blanco:
perl -lane 'print join " ", @F[1, 0]' in_file
Aquí,
-ele dice a Perl que busque el código en línea, en lugar de en un archivo de script separado,
-nlee la línea de entrada 1 a la vez,
-lelimina el separador de registro de entrada ( \nen * NIX) después de leer la línea (similar a chomp) y agrega salida separador de registros ( \nen * NIX) para cada uno print,
-adivide la línea de entrada en el espacio en blanco en la matriz @F,
-F'\t'en combinación con -ala línea de entrada en las TAB, en lugar del espacio en blanco en la matriz @F.
@F[1, 0]es la matriz compuesta de los elementos segundo y primero de la matriz @F, en este orden. Recuerde que las matrices en Perl están indexadas a cero, mientras que los campos cutestán indexados a 1. Por lo tanto, los campos en @F[0, 1]son los mismos campos que en cut -f1,2.
Tenga en cuenta que dicha notación permite una manipulación más flexible de la entrada que en algunas otras respuestas publicadas anteriormente (que están bien para una tarea simple). Por ejemplo:
# reverses the order of fields:
perl -F'\t' -lane 'print join "\t", reverse @F' in_file
# prints last and first fields only:
perl -F'\t' -lane 'print join "\t", @F[-1, 0]' in_file
cutque no admita este comando intuitivo de reordenamiento. De todos modos, otro consejo: se puede utilizarawk's-FSy-OFSopciones para el uso de entrada personalizada y separadores de campo de salida (como-dy--output-delimiterparacut).