Обратный файл в оболочке Unix

У меня есть файл parse.txt

parse.txt содержит следующие

remo/hello/1.0,remo/hello2/2.0,remo/hello3/3.0,whitney/hello/1.0,julie/hello/2.0,julie/hello/3.0

и я хочу, чтобы файл output.txt как (чтобы отменить порядок от последнего к первому), используя parse.txt

julie/hello/3.0,julie/hello/2.0,whitney/hello/1.0,remo/hello3/3.0,remo/hello2/2.0,remo/hello/1.0

Я пробовал следующий код:

tail -r parse.txt 

Ответ 1

Вы можете использовать эту команду awk:

awk -v RS=, '{a[++i]=$1} END{for (k=i; k>=1; k--) printf a[k] (k>1?RS:ORS)}' parse.txt
julie/hello/3.0,julie/hello/2.0,whitney/hello/1.0,remo/hello3/3.0,remo/hello2/2.0,remo/hello/1.0

Ответ 2

Вы можете использовать удивительно полезный tac от GNU Coreutils.

tac -s "," parse.txt > newparse.txt

tac по умолчанию будет "cat" файл стандартным, реверсив строки. Задав разделитель, используя флаг -s, вы можете просто поменять свои поля по своему желанию.

(Возможно, вам понадобится выполнить шаг после обработки, чтобы получить правильное представление запятых, что может стать еще одним шагом в вашем конвейере.)

Ответ 3

Мне нравится решение tac; он жесткий и элегантный, но, как отметил Мика, tac является частью GNU Coreutils, что означает, что он недоступен по умолчанию во FreeBSD, OSX, Solaris и т.д.

Это можно сделать в чистом bash, никаких внешних инструментов не требуется.

#!/usr/bin/env bash

unset comma
read foo < parse.txt
bar=(${foo//,/ })
for (( count="${#bar[@]}"; --count >= 0; )); do
  printf "%s%s" "$comma" "${bar[$count]}"
  comma=","
done

Это, очевидно, обрабатывает только одну строку, на ваш образец ввода. Вы можете его обернуть, если вам нужно обрабатывать несколько строк ввода.

Логика здесь заключается в том, что мы можем преобразовать вход в массив, заменив запятые пробелами. Конечно, если бы наши входные данные включали пробелы, это нужно было бы скорректировать. После того, как мы получим массив, мы просто переходим через него, печатая каждую запись.

Обратите внимание, что это не включает завершающую новую строку. Если вы хотите, вы можете добавить его с помощью:

printf '\n'

в качестве окончательной строки.

Ответ 4

perl -F, -lane 'print join ",", reverse @F' parse.txt > output.txt

Ответ 5

Вопрос помечен и вы упомянули tail -r, в котором говорится, что вы не можете использовать Linux (с полной GNU toolchain), но вместо этого какой-то "реальный" Unix (вариант BSD), например .

Таким образом, команда tac недоступна, но, как упоминалось в вопросе, tail -r is. Поэтому вы можете использовать следующее:

$ tr ',' '\n' < parse.txt | tail -r | tr '\n' ',' | sed 's/,$//'
julie/hello/3.0,julie/hello/2.0,whitney/hello/1.0,remo/hello3/3.0,remo/hello2/2.0,remo/hello/1.0
$ 

Примечания:

  • Это работает только для файлов с одной строкой, поскольку мы полагаемся на преобразование запятых в новые строки и обратно. Если имеется более одной строки, то новые строки между ними будут преобразованы в запятые второй tr.
  • Конечный sed должен удалить конечную запятую, которая была преобразована из конечной новой строки, вставленной tail

Ответ 6

Вы можете использовать любой язык для этого

xargs ruby -e "puts ARGV[0].split(',').reverse.join(',')" < parse.txt

Ответ 7

Эмуляция tac с помощью sed:

tr , '\n' <parse.txt | sed '1!G; h; $!d' | paste -sd ,

В качестве альтернативы, если у вас нет paste:

tr , '\n' <parse.txt | sed '1!G; h; $!d' | tr '\n' , | sed 's/,$//'

Вывод:

julie/hello/3.0,julie/hello/2.0,whitney/hello/1.0,remo/hello3/3.0,remo/hello2/2.0,remo/hello/1.0

Ответ 8

Реверс можно сделать с помощью tac (от cat). Как прокомментировано, это изменит линии, на которые не запросил ОП.

tac filename

Вы все равно можете tac, если вы предоставляете строку за строкой и наоборот, а не ограничитель строки, но разделитель полей, здесь ,.

echo "a,b,c" | tr '\n' ',' | tac -s "," | sed 's/,$/\n/'