W jaki sposób 2 nieposortowane pliki tekstowe o różnej długości mogą być wyświetlane obok siebie (w kolumnach) w plikushell
Podano one.txt
i two.txt
:
$ cat one.txt
apple
pear
longer line than the last two
last line
$ cat two.txt
The quick brown fox..
foo
bar
linux
skipped a line
Pokaz:
apple The quick brown fox..
pear foo
longer line than the last two bar
last line linux
skipped a line
paste one.txt two.txt
prawie załatwia sprawę, ale nie wyrównuje ładnie kolumn, ponieważ po prostu wypisuje jedną tabulację między kolumnami 1 i 2. Wiem, jak to zrobić z emacsem i vimem, ale chcę, aby wyjście było wyświetlane na standardowe wyjście dla potoku itp.
Rozwiązanie, które wymyśliłem, używa, sdiff
a następnie rur do seda, aby usunąć wyjście, sdiff
dodaje.
sdiff one.txt two.txt | sed -r 's/[<>|]//;s/(\t){3}//'
Mógłbym stworzyć funkcję i umieścić ją w moim, .bashrc
ale na pewno polecenie do tego już istnieje (lub potencjalnie czystsze rozwiązanie)?
linux
shell
unix
command-line
gnu-coreutils
Chris Seymour
źródło
źródło
Odpowiedzi:
Możesz
pr
to zrobić, używając-m
flagi do łączenia plików, po jednym na kolumnę, i-t
pomijania nagłówków, np.wyjścia:
Zobacz też:
źródło
pr
. Próbowałem z 3 plikami i dane wyjściowe zostały obcięte, ale-w
opcja rozwiązała ten problem. Niezła odpowiedź.$COLUMNS
, co powinno być dostarczone przez powłokę.pr
odcina końce długich linii. Czy istnieje sposób, aby zawijał linie?Aby nieco rozwinąć odpowiedź @Hasturkun : domyślnie
pr
używa tylko 72 kolumn do wyjścia, ale stosunkowo łatwo jest sprawić, by używał wszystkich dostępnych kolumn w oknie terminala:pr -w $COLUMNS -m -t one.txt two.txt
Większość powłok będzie przechowywać (i aktualizować) szerokość ekranu twojego terminala w
$COLUMNS
zmiennej środowiskowej, więc po prostu przekazujemy tę wartość dopr
ustawienia szerokości wyjścia.To również odpowiada na pytanie @Matta :
Więc nie:
pr
sam nie może wykryć szerokości ekranu, ale pomagamy trochę, przekazując szerokość terminala za pomocą-w
opcji.źródło
Jeśli znasz pliki wejściowe nie mają kart, a następnie przy użyciu
expand
upraszcza @oyss „s odpowiedź :Jeśli w plikach wejściowych mogą znajdować się zakładki, zawsze możesz najpierw rozwinąć:
źródło
paste one.txt two.txt | awk -F'\t' '{ if (length($1)>max1) {max1=length($1)}; col1[NR] = $1; col2[NR] = $2 } END {for (i = 1; i<=NR; i++) {printf ("%-*s %s\n", max1, col1[i], col2[i])} }'
Użycie
*
w specyfikacji formatu umożliwia dynamiczne podawanie długości pola.źródło
diff -y one.txt two.txt
działa lepiej niżpaste one.txt two.txt
usuwanie dodatkowych znaków różnicowych, które są wyświetlane,sed
jest trywialne w porównaniu z pisaniem / zapamiętywaniemawk
skryptu. Nawet z obydwoma funkcjami na.bash_rc
dłużej! = Lepiej, bardziej czytelnie, szybciej… jaka jest tutaj zaleta?usuń dynamicznie zliczanie długości pól z odpowiedzi Barmara sprawi, że polecenie będzie znacznie krótsze ... ale nadal potrzebujesz co najmniej jednego skryptu, aby zakończyć pracę, której nie można było uniknąć bez względu na wybraną metodę.
paste one.txt two.txt |awk -F'\t' '{printf("%-50s %s\n",$1,$2)}'
źródło
Jeśli chcesz poznać rzeczywistą różnicę między dwoma plikami obok siebie, użyj
diff -y
:Możesz również ustawić szerokość wyjściową za pomocą
-W, --width=NUM
opcji:i aby
diff
dopasować kolumny wyjściowe do bieżącego okna terminala:diff -y -W $COLUMNS file1.cf file2.cf
źródło
Jest
sed
sposób:f1width=$(wc -L <one.txt) f1blank="$(printf "%${f1width}s" "")" paste one.txt two.txt | sed " s/^\(.*\)\t/\1$f1blank\t/; s/^\(.\{$f1width\}\) *\t/\1 /; "
Pod grzmotnąćmożesz użyć
printf -v
:f1width=$(wc -L <one.txt) printf -v f1blank "%${f1width}s" paste one.txt two.txt | sed "s/^\(.*\)\t/\1$f1blank\t/; s/^\(.\{$f1width\}\) *\t/\1 /;"
(Oczywiście rozwiązanie @Hasturkun
pr
jest najdokładniejsze !) :Zaleta
sed
ponadpr
Możesz precyzyjnie wybrać szerokość separacji i / lub separatory:
f1width=$(wc -L <one.txt) (( f1width += 4 )) # Adding 4 spaces printf -v f1blank "%${f1width}s" paste one.txt two.txt | sed "s/^\(.*\)\t/\1$f1blank\t/; s/^\(.\{$f1width\}\) *\t/\1 /;"
Lub, na przykład, zaznacz linie zawierające
line
:f1width=$(wc -L <one.txt) printf -v f1blank "%${f1width}s" paste one.txt two.txt | sed "s/^\(.*\)\t/\1$f1blank\t/; /line/{s/^\(.\{$f1width\}\) *\t/\1 |ln| /;ba}; s/^\(.\{$f1width\}\) *\t/\1 | | /;:a"
wyrenderuje:
źródło
Znajdź poniżej rozwiązanie oparte na Pythonie.
import sys # Specify the number of spaces between the columns S = 4 # Read the first file l0 = open( sys.argv[1] ).read().split('\n') # Read the second file l1 = open( sys.argv[2] ).read().split('\n') # Find the length of the longest line of the first file n = len(max(l0, key=len)) # Print the lines for i in xrange( max( len(l0), len(l1) ) ): try: print l0[i] + ' '*( n - len(l0[i]) + S) + l1[i] except: try: print ' ' + ' '*( n - 1 + S) + l1[i] except: print l0[i]
Przykład
źródło
diff -y <file1> <file2> [root /]# cat /one.txt
[root /]# cat /two.txt
[root@RHEL6-64 /]# diff -y one.txt two.txt
źródło
sdiff
Jestdiff -y
które omówię w pytaniu.diff
dodaje znaki między dwoma plikami.