Відповіді:
Для cut(1)чоловічої сторінки:
Використовуйте один, і лише один із -b, -c або -f. Кожен СПИСОК складається з одного діапазону або багатьох діапазонів, розділених комами. Вибране введення записується в тому ж порядку, що і прочитане, і пишеться рівно один раз.
Спочатку воно доходить до поля 1, тобто друкується, а потім - поле 2.
Використовуйте awkзамість цього:
awk '{ print $2 " " $1}' file.txt
FSце варіант, OFSце змінна. наприкладawk -v OFS=";" -F"\t" '{print $2,$1}'
| sed 's/\r//' | awk
awk '{print $4 "\t" $2 "\t" $6 "\t" $7}' file
Ви також можете комбінувати cutта paste:
paste <(cut -f2 file.txt) <(cut -f1 file.txt)
через коментарі: Можна уникнути башизмів і видалити один екземпляр вирізання, виконавши:
paste file.txt file.txt | cut -f2,3
cutдобре працює для стовпців змінної довжини, якщо у вас є унікальний роздільник стовпців.
bashізмів та видалити один екземпляр cut, виконуючи такі дії: paste file.txt file.txt | cut -f2,3
використовуючи лише оболонку,
while read -r col1 col2
do
echo $col2 $col1
done <"file"
"$col2"і "$col1"- у даних можуть бути метахарактеристики оболонок або інші шенагігани.
Ви можете використовувати Perl для цього:
perl -ane 'print "$F[1] $F[0]\n"' < file.txt
Перевага запуску perl полягає в тому, що (якщо ви знаєте Perl) ви можете зробити набагато більше обчислень на F, ніж перестановка стовпців.
perl -ae printпрацює як catдля мене
Використання join:
join -t $'\t' -o 1.2,1.1 file.txt file.txt
Примітки:
-t $'\t'У GNU join більш інтуїтивним -t '\t' без$ збою ( Coreutils v8.28 і раніше?); це, мабуть, помилка, яка потрібна для вирішення проблеми $. Див.: Універсальний розділовий знак розділення .
joinпотрібні дві назви файлів, хоча над цим файлом працює лише один файл. Використання однойменної назви двічі хитрощів joinвиконувати бажану дію.
Для систем з низькими ресурсами joinпропонується менший слід, ніж деякі інструменти, що використовуються в інших відповідях:
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/perlПросто працюю над чимось дуже схожим, я не експерт, але я думав, що поділюсь командами, якими я користувався. У мене був мульти стовпець csv, від якого мені потрібно було лише 4 стовпчики, а потім мені потрібно було їх змінити.
У моєму файлі була труба '|' обмежено, але це можна замінити.
LC_ALL=C cut -d$'|' -f1,2,3,8,10 ./file/location.txt | sed -E "s/(.*)\|(.*)\|(.*)\|(.*)\|(.*)/\3\|\5\|\1\|\2\|\4/" > ./newcsv.csv
Дійсно, це дійсно грубо і готово, але його можна підлаштувати під костюм!
Використання sed
Використовуйте sed з вкладеними субдекспресіями основного регулярного вираження для збору та зміни порядку змісту стовпця. Цей підхід найкраще підходить, коли є обмежена кількість скорочень для впорядкування стовпців, як у цьому випадку.
Основна ідея полягає в оточенні цікавих частин шаблону пошуку з \(і \), які можна відтворити в шаблоні заміни, \#де #являє собою послідовне положення підвираження в шаблоні пошуку.
Наприклад:
$ echo "foo bar" | sed "s/\(foo\) \(bar\)/\2 \1/"
врожайність:
bar foo
Текст поза піддекспресією сканується, але не зберігається для відтворення в рядку заміни.
Хоча питання не стосувалося стовпців із фіксованою шириною, ми обговоримо тут, оскільки це гідна міра будь-якого заданого рішення. Для простоти припустимо, що файл обмежений простором, хоча рішення можна розширити для інших роздільників.
Розбіжні простори
Щоб проілюструвати найпростіше використання, припустимо, що декілька пробілів можна зібрати на одиничні пробіли, а значення другого стовпця закінчуються EOL (а не пробілом).
Файл:
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
Перетворити:
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
Збереження ширини стовпців
Давайте тепер поширимо метод на файл із стовпцями постійної ширини, дозволяючи колонкам бути різної ширини.
Файл:
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
Перетворити:
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
Нарешті, хоча приклад запитання не має рядків неоднакової довжини, цей вираз sed підтримує цей випадок.
Файл:
bash-3.2$ cat f3
Column1 Column2
str1 1
string2 2
str3 3
Перетворити:
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
Порівняння з іншими методами упорядкування стовпців під оболонкою
Дивно, але інструмент для обробки файлів, awk не дуже підходить для вирізання з поля до кінця запису. У sed це можна досягти, використовуючи регулярні вирази, наприклад, \(xxx.*$\)де xxxвираз відповідає стовпцю.
Використання вставлених і вирізаних підшах стає складним при впровадженні всередину скриптів оболонки. Код, який працює з командного рядка, не може проаналізувати, коли він введений всередині сценарію оболонки. Принаймні, це був мій досвід (який підштовхував мене до такого підходу).
Розширення на відповідь від @Met, також за допомогою Perl:
Якщо вхід і вихід обмежені TAB:
perl -F'\t' -lane 'print join "\t", @F[1, 0]' in_file
Якщо вхід і вихід обмежені пробілом:
perl -lane 'print join " ", @F[1, 0]' in_file
Тут,
-eкаже Perl шукати вбудований код, а не в окремому файлі сценарію,
-nчитає вхід 1 рядок за один раз,
-lвидаляє роздільник запису вхідних даних ( \nна * NIX) після зчитування рядка (аналогічно chomp) та додає вихід роздільник записів ( \nна * NIX) кожен print,
-aрозділяє вхідні лінію на пробільних в масив @F,
-F'\t'в комбінації з-a розколами вхідний лінії на ТКСЕ, замість пробілів в масив @F.
@F[1, 0]- це масив, що складається з 2-го та 1-го елементів масиву @Fв цьому порядку. Пам'ятайте, що масиви в Perl є індексованими нулем, тоді як поля в cut- 1-індексованими. Так поля в@F[0, 1] - ті ж поля, що і поля в cut -f1,2.
Зауважте, що такі позначення дозволяють гнучкіше маніпулювати введенням, ніж у деяких інших відповідях, розміщених вище (що чудово підходить для простого завдання). Наприклад:
# 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
cut, не підтримує цю інтуїтивну команду переупорядкування. У будь-якому разі, ще одна порада: ви можете використовуватиawk's-FSта-OFSпараметри для використання спеціальних роздільників поля введення та виведення (як-dі--output-delimiterдляcut).