У меня есть файл в следующем формате
Столбец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
Здесь
-ePerl сообщает 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и-OFSoptions для использования настраиваемых разделителей полей ввода и вывода (например,-dи--output-delimiterдляcut).