У меня есть файл в следующем формате
Столбец1 Столбец2 ул1 1 ул2 2 ул3 3
Я хочу, чтобы столбцы переставили. Я пробовал команду ниже
вырезать -f2,1 file.txt
Команда не меняет порядок столбцов. Есть идеи, почему это не работает?
Спасибо.
У меня есть файл в следующем формате
Столбец1 Столбец2 ул1 1 ул2 2 ул3 3
Я хочу, чтобы столбцы переставили. Я пробовал команду ниже
вырезать -f2,1 file.txt
Команда не меняет порядок столбцов. Есть идеи, почему это не работает?
Спасибо.
Ответы:
Для cut(1)
страницы руководства :
Используйте один и только один из -b, -c или -f. Каждый СПИСОК состоит из одного диапазона или нескольких диапазонов, разделенных запятыми. Выбранный ввод записывается в том же порядке, в котором он читается, и записывается ровно один раз.
Сначала он достигает поля 1, так что оно печатается, а затем поле 2.
awk
Вместо этого используйте :
awk '{ print $2 " " $1}' file.txt
FS
это вариант, OFS
это переменная. egawk -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)
через комментарии: можно избежать башизмов и удалить один экземпляр cut, выполнив:
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 и раньше?); вероятно, это ошибка, требующая обходного пути $
. См .: unix join separator char .
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
Transform:
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
Transform:
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
Transform:
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:
Если ввод и вывод разделены табуляцией:
perl -F'\t' -lane 'print join "\t", @F[1, 0]' in_file
Если ввод и вывод разделены пробелами:
perl -lane 'print join " ", @F[1, 0]' in_file
Здесь
-e
Perl сообщает Perl искать код в строке, а не в отдельном файле сценария,
-n
считывает ввод по одной строке за раз,
-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
options для использования настраиваемых разделителей полей ввода и вывода (например,-d
и--output-delimiter
дляcut
).