Принудительный перевод строки с помощью подстановочного знака cat

9

Я хочу использовать cat с подстановочными знаками в bash, чтобы напечатать несколько маленьких файлов (каждый файл - одно предложение) для стандартного вывода. Однако содержимое отдельного файла не разделено новой строкой, которую я хотел бы для удобства чтения.

Как добавить какой-либо разделитель файлов к этой команде?

lennyklb
источник

Ответы:

12

Определите функцию оболочки, которая выводит конец строки после каждого файла, и используйте ее вместо cat:

endlcat() {
  for file in "$@"; do
    cat -- "$file"
    echo
  done
}

тогда вы можете использовать endlcat *.

В forпетле петли над всеми предусмотренными аргументами ( $@) , которые уже сбежавших оболочкой при использовании маски , как *. --Требуется не подавиться именами файлов , начинающихся с тиром. Наконец echoвыводит новую строку.

Marco
источник
Кажется довольно очевидным использовать итерацию в ретроспективе! Я подумал, что у кошки мог быть флаг, но это тоже работает! Спасибо.
lennyklb
Вам не нужно in "$@"- это неявно.
10
4
Быть явным хорошо для удобства чтения.
Cas
5

Просто используйте цикл вместо простого cat:

for file in /path/to/targetdir/*; do
    echo "-------- $file -------"
    cat "$file" 
done
Тердон
источник
Работает как принятый ответ, но у этого также был следующий шаг к командной строке, поэтому я принял другой.
lennyklb
3

Если вы хотите, чтобы имя файла между файлами, используя tail:

tail -n +1 ./*

(Если вы хотите tacвместо cat, некоторые tailреализации имеют -rопцию для эквивалентного tacфункционала)

cuonglm
источник
3

Это будет работать:

sed '' -- *

Вам не нужны никакие циклы оболочки или что-то иное, и это всегда будет следовать за выводом файла с \newline - за исключением, возможно, самого последнего.

В противном случае, если вы хотите, чтобы между выходными данными каждого файла выводилась пустая строка, это может сработать:

bpaste(){
    eval "paste -'sd\n' -- $(x=0;for f do printf "\"\${$((x+=1))}\" - ";done)"
}   </dev/null

Это всегда будет следовать за выводом файла с \newline и дополнительной пустой строкой.

Вы можете назвать это как:

bpaste *
mikeserv
источник
@cuonglm - оператору нужна новая строка между файлами. это обеспечивает новую строку между файлами.
mikeserv
@cuonglm - попробуйте еще раз. for n in 1 2 3; do printf "$n" >"$n"; done; sed '' -- [123]
mikeserv
@cuonglm - любой sedдолжен всегда печатать \newline, прежде чем он напечатает что-либо еще, хотя последняя строка последнего файла может не добавить \newline. Я мог бы поклясться, что я ответил на этот вопрос раньше.
mikeserv
@cuonglm - я не понимаю, что вы имеете в виду. ту маленькую раковину, которую я только что дал тебе отпечатки 1\n2\n3. оно работает. это всегда так. что это печатает для вас?
mikeserv
1
@DennisWilliamson: Использование \nв RHS не является стандартным. Вы можете использовать sed -e '$G'.
cuonglm
2

Как и в ответе @terdon , если вы предпочитаете видеть имя файла в будущем, вы можете использовать headкоманду:

$ head *file*
==> file_1 <==
file 1 content

==> file_2 <==
file 2 content

==> file_3 <==
file 3 content

headпо умолчанию - первые 10 строк, поэтому использовать его без параметров команды для вашего случая (одно предложение на файл) вполне нормально. В противном случае вам нужна -n Xопция.

ХИК
источник
2

Другой способ - использовать grep -hпросто поиск пустой строки в каждом файле. Это будет соответствовать всем строкам, независимо от того, сколько строк завершено или нет. Результаты grep всегда заканчиваются символом новой строки. В -hопции подавляет предваряя каждую строку вывода с именем файла он пришел из:

$ printf 'a' > a
$ printf 'b\nB' > b
$ printf 'c\n' > c
$ ls
a  b  c
$ cat -- *
ab
Bc
$ grep -h '' *
a
b
B
c
$ 

Или вы можете использовать GNU pasteв -sрежиме erial с символом новой строки в качестве разделителя:

$ paste -s -d '\n' -- *
a
b
B
c
$ 
Цифровая травма
источник