Преобразование файла, разделенного пробелом, в файл, разделенный табуляцией

#awk

#awk

Вопрос:

Я пытался использовать awk для преобразования файла, разделенного пробелом, в файл, разделенный табуляцией. К моему удивлению, это сработало не так, как ожидалось:

 awk -vOFS=

Я ожидал чего-то подобного:

 item    gram
tomato  500
orange  1500
bread   2000
 

Чего мне не хватает?

Примечание: многие предложили несколько альтернатив, вот некоторые из них, возможно, кому-то это интересно.

 tr -s " " "t" <column.txt

column -t <column.txt

perl -ple "s/s /t/g" <column.txt

sed "s/s /t/" <column.txt

ruby -ple 'gsub(/s /,"t")' <column.txt

python -c "import sys,re; [ sys.stdout.write(re.sub(r'  ','t',l)) for l in sys.stdin ]" <column.txt
 

Комментарии:

1. Лично я просто использую perl -pli -e 's/s /t/g' file.txt .

2. @Shawn, спасибо, я бы предпочел это, но у меня не было Perl в этой среде. В итоге я использовал tr -s " " "t" <column.txt . Это более или менее академический вопрос, поэтому я могу понять, что происходит.

3. чтобы добавить к хорошему ответу от @Jotne, вам не хватает одной вещи: print эквивалентно print $0 , что является только одним полем. Я считаю, что это лучше объясняет фразу "если вы просто установите OFS, он ничего не сделает". Он действительно что-то делает, вы просто не используете его. Кстати, это можно было бы улучшить, используя FS для вырезания столбцов из вашего файла и последующего вывода print $1,$2 , что явно использует OFS .

4. @DaemonPainter из документации $ 0 означает полную запись, а не поле, и я предположил, что она отличается от $ 1, $ 2 ... и т.д.

5. да, действительно. В конце концов, все, что $x вы просите напечатать, выводится в одно поле. Таким образом, только для печати $0 не будет использоваться разделитель полей вывода. Когда я говорю, что print $1,$2 это явно использует OFS , это происходит из-за запятой. Напомним, что для того, чтобы иметь разделитель полей вывода, вам необходимо вывести как минимум два поля. print или print $0 выводит только один.

Ответ №1:

Попробуйте это:

 awk -v OFS='t' '{$1=$1}1' file
 

Если вы просто установите OFS, он ничего не сделает. При установке $1 на $1 него будет использоваться поле OFS since, поскольку оно изменилось. 1 всегда имеет значение true, поэтому он будет печатать строку. То же, что {print}

Комментарии:

1. Этому есть более простое объяснение, и оно приводится в комментариях под исходным вопросом. В программировании нет необходимости угадывать, многое из этого сводится к хорошим объясненным правилам.

Ответ №2:

 awk -v OFS='t' '{$1=$1}1' file
 

может быть дополнительно сокращен до

 mawk 'BEGIN {OFS="t"} (NF==1) || ($1=$1)' file.
 

$ 1 = $ 1 не является бесплатным. NF==1 обойдет его для любой строки, в которой просто нет пробелов (просто более гибкое универсальное решение). Успешный $1 = $1 возвращает true, поэтому дополнительный } 1' вне фигурных скобок немного излишен.

t' '{print}' column.txt
item gram
tomato 500
orange 1500
bread 2000
Я ожидал чего-то подобного:


Чего мне не хватает?

Примечание: многие предложили несколько альтернатив, вот некоторые из них, возможно, кому-то это интересно.


Комментарии:

1. Лично я просто использую perl -pli -e 's/s /t/g' file.txt .

2. @Shawn, спасибо, я бы предпочел это, но у меня не было Perl в этой среде. В итоге я использовал tr -s " " "t" <column.txt . Это более или менее академический вопрос, поэтому я могу понять, что происходит.

3. чтобы добавить к хорошему ответу от @Jotne, вам не хватает одной вещи: print эквивалентно print $0 , что является только одним полем. Я считаю, что это лучше объясняет фразу «если вы просто установите OFS, он ничего не сделает». Он действительно что-то делает, вы просто не используете его. Кстати, это можно было бы улучшить, используя FS для вырезания столбцов из вашего файла и последующего вывода print $1,$2 , что явно использует OFS .

4. @DaemonPainter из документации $ 0 означает полную запись, а не поле, и я предположил, что она отличается от $ 1, $ 2 … и т.д.

5. да, действительно. В конце концов, все, что $x вы просите напечатать, выводится в одно поле. Таким образом, только для печати $0 не будет использоваться разделитель полей вывода. Когда я говорю, что print $1,$2 это явно использует OFS , это происходит из-за запятой. Напомним, что для того, чтобы иметь разделитель полей вывода, вам необходимо вывести как минимум два поля. print или print $0 выводит только один.

Ответ №1:

Попробуйте это:


Если вы просто установите OFS, он ничего не сделает. При установке $1 на $1 него будет использоваться поле OFS since, поскольку оно изменилось. 1 всегда имеет значение true, поэтому он будет печатать строку. То же, что {print}

Комментарии:

1. Этому есть более простое объяснение, и оно приводится в комментариях под исходным вопросом. В программировании нет необходимости угадывать, многое из этого сводится к хорошим объясненным правилам.

Ответ №2:


может быть дополнительно сокращен до


$ 1 = $ 1 не является бесплатным. NF==1 обойдет его для любой строки, в которой просто нет пробелов (просто более гибкое универсальное решение). Успешный $1 = $1 возвращает true, поэтому дополнительный } 1′ вне фигурных скобок немного излишен.