Ответ 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
У меня есть файл 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
Вы можете использовать эту команду 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
Вы можете использовать удивительно полезный tac
от GNU Coreutils.
tac -s "," parse.txt > newparse.txt
tac
по умолчанию будет "cat" файл стандартным, реверсив строки. Задав разделитель, используя флаг -s
, вы можете просто поменять свои поля по своему желанию.
(Возможно, вам понадобится выполнить шаг после обработки, чтобы получить правильное представление запятых, что может стать еще одним шагом в вашем конвейере.)
Мне нравится решение 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'
в качестве окончательной строки.
perl -F, -lane 'print join ",", reverse @F' parse.txt > output.txt
Вопрос помечен unix и вы упомянули tail -r
, в котором говорится, что вы не можете использовать Linux (с полной GNU toolchain), но вместо этого какой-то "реальный" Unix (вариант BSD), например osx.
Таким образом, команда 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
Вы можете использовать любой язык для этого
xargs ruby -e "puts ARGV[0].split(',').reverse.join(',')" < parse.txt
Эмуляция 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
Реверс можно сделать с помощью tac (от cat). Как прокомментировано, это изменит линии, на которые не запросил ОП.
tac filename
Вы все равно можете tac
, если вы предоставляете строку за строкой и наоборот, а не ограничитель строки, но разделитель полей, здесь ,
.
echo "a,b,c" | tr '\n' ',' | tac -s "," | sed 's/,$/\n/'