Вы можете использовать IFS=newline (предполагая, что ни одно имя файла не содержит newline), но вы должны установить его во внешней оболочке ДО подстановки:
$ ls -1
a file with spaces
able
alpha
baker
boo hoo hoo
bravo
$ # note semicolon here; it's not enough to be in the environment passed
$ # to printf, it must be in the environment OF THE SHELL WHILE PARSING
$ IFS=$'\n'; printf '%s\n' --afiles $(find . -name 'a*') --bfiles $(find . -name 'b*')
--afiles
./able
./a file with spaces
./alpha
--bfiles
./bravo
./boo hoo hoo
./baker
С zsh
, но не bash
вы можете использовать и null $'\0'
. Даже в bash
можно обработать newline, если есть один достаточно странный символ, который никогда не используется, например
IFS=$'\1'; ... $(find ... -print0 | tr '\0' '\1') ...
Однако, этот подход не обрабатывает дополнительную просьбу, которую вы сделали в комментариях к ответу @steeldriver, опустить --afiles, если find a пуст.
Я не знаю, считаете ли вы это хорошим ответом, но...
Почему вы не используете базу данных для решения этой проблемы? вы можете импортировать свой набор данных как временную таблицу, а затем выполнить
SELECT column1, column2, ... column-n FROM my_temp_table
Вы можете использовать другие фильтры или преобразования по мере необходимости. Затем вы можете переформатировать вывод по своему усмотрению.
Все эти задачи можно было бы запрограммировать в виде bash-скрипта и объединить выходные данные с помощью конвейеров.
Иногда я использовал команду «pv», чтобы увидеть прогресс вывода между командами.
Чтобы импортировать набор данных, вы можете запрограммировать ETL с помощью Pentaho Data Integration.
Использование модуля Perl Sort::Naturally
для ввода данных
ID M2 M5 M8 M1 M3 M9 M700000
A1 m1,2 m1,5 m1,8 m1,1 m1,3 m1,9 m1,7000000
A2 m2,2 m2,5 m2,8 m2,1 m2,3 m2,9 m2,7000000
A3 m3,2 m3,5 m3,8 m3,1 m3,3 m3,9 m3,7000000
A1000 m1000,2 m1000,5 m1000,8 m1000,1 m1000,3 m1000,9 m1000,7000000
perl -MSort::Naturally -lane '
if ($. == 1) {
@indices = (0, map { $_->[0] }
sort { ncmp($a->[1], $b->[1]) }
map { [$_, $F[$_]] }
1..$#F
);
$, = " ";
}
print @F[@indices]
' test.data
выход
ID M1 M2 M3 M5 M8 M9 M700000
A1 m1,1 m1,2 m1,3 m1,5 m1,8 m1,9 m1,7000000
A2 m2,1 m2,2 m2,3 m2,5 m2,8 m2,9 m2,7000000
A3 m3,1 m3,2 m3,3 m3,5 m3,8 m3,9 m3,7000000
A1000 m1000,1 m1000,2 m1000,3 m1000,5 m1000,8 m1000,9 m1000,7000000
Возможно, это тоже поможет вам.
Пример:
$ echo "ID M2 M5 M8 M1 M3 M9 .....M7000000
Animal1 1 0 2 1 0 2 .....1
Animal2 0 1 2 0 1 1 .....0
Animal3 2 1 0 1 2 1 .....0
.
.
.
.
Animaln" | awk '
{
for (i=1; i<=NF; i++) {
a[NR,i] = $i
}
}
NF>p { p = NF }
END {
for(j=1; j<=p; j++) {
str=a[1,j]
for(i=2; i<=NR; i++){
str=str" "a[i,j];
}
print str
}
}' | sort -n | awk '
{
for (i=1; i<=NF; i++) {
a[NR,i] = $i
}
}
NF>p { p = NF }
END {
for(j=1; j<=p; j++) {
str=a[1,j]
for(i=2; i<=NR; i++){
str=str" "a[i,j];
}
print str
}
}'
ID M1 M2 M3 M5 .....M7000000 M8 M9
Animal1 1 1 0 0 .....1 2 2
Animal2 0 0 1 1 .....0 2 1
Animal3 1 2 2 1 .....0 0 1
.
.
.
.
Animaln
Если у вас есть GNU awk
, вы можете попробовать это:
NR == 1 {
for (i = 2; i <= NF; i++) {
columns[substr($i, 2)] = i;
}
count = asorti(columns, sorted, "@ind_num_asc");
printf("%s", $1);
for (i = 1; i <= count; i++) {
printf(" M%s", sorted[i]);
indx[i] = columns[sorted[i]];
}
print "";
next;
}
{
printf("%s", $1);
for (i = 1; i <= count; i++) {
printf(" %s", $(indx[i]));
}
print "";
}
В Python:
from csv import DictReader, DictWriter
with open('in_file.csv') as infile, open('out_file.csv') as outfile:
reader = DictReader(infile)
writer = DictReader(outfile, fieldnames=sorted(reader.fieldnames))
writer.writerows(reader)
С GNUdatamash
и GNUsort
:
datamash transpose -t ' ' -H <file_in.csv | sort -V | datamash transpose -t ' ' -H >file_out.csv
Это прекрасно работает для «достаточно малых» данных. Это может или не может работать с вашим файлом.
Редактировать:Приведенные ниже решения без транспозиций должны быть менее ресурсоемкими -.
perl -pale '
$. == 1 and
@I = map { $_->[1] }
sort { $a->[0] <=> $b->[0] }
map { [ $F[$_] =~ /^M(\d+)$/, $_ ] } 1..$#F;
$_ = "@F[0, @I]";
' yourlargefile
M
, встречающейся в начале, используя хорошо известную Schwartzian maneuver
. Это дает нам индексы, переупорядоченные так, чтобы столбцы выходили в численно отсортированном порядке (M1, M2, M3,...)@I
, для повторного -размещения элементов @F
. -p
в Perl включает автопечать содержимого $_
, -l
добавляет newline
. Если у вас установлена утилитаrs
, вы можете сделать это:
rs -c' ' -T | {
stdbuf -i0 sed "1q"
sort -V
} | rs -C' ' -T
Или все в одной строке:
rs -c' ' -T | { stdbuf -i0 sed "1q"; sort -V ; } | rs -C' ' -T
rs
транспонирует входные данные (с разделенными пробелами -полями)sed
читает первую строку, выводит ее, затем завершает работу, оставляя остальную часть конвейера из rs
нетронутой. stdbuf
требуется для обеспечения того, чтобы sed
читал только до первой новой строки и не далее, отключив буферизацию ввода sort
остальные строки rs
транспонирует результирующий поток обратно в исходный формат. rs
устанавливается по умолчанию в MacOS. В системах Linux вам может потребоваться установить его -, например.
sudo apt install rs
Предупреждение:stdbuf
и sort
s -V
относятся к GNU -, поэтому они не будут работать на немодифицированной MacOS.