Расположение и содержимое выходного файла на основе списка файлов

У меня есть файл, содержащий местоположения разных файлов, называемых locationfile.txt который содержит:

 /home/user/documents/file1 /home/user/file2 /home/user/file3 

Каждый текстовый файл имеет около 10 строк, и я хочу вывести все файлы в другой файл с именем finalfile .

Я понял, что если я это сделаю

 cat locationfile.txt | while read line; do cat "$line"; done 

Это печатает все файлы вместе, поэтому он становится текстовым файлом ~ 30 строк.

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

 /home/user/documents/file1 text text text "" /home/user/file2 text text text "" /home/user/file3 text text text "" 

6 Solutions collect form web for “Расположение и содержимое выходного файла на основе списка файлов”

Перед тем, как cat сделает echo или printf имени файла:

 while read line; do printf '%s\n' "$line"; cat "$line"; done <locationfile.txt >finalfile 

Или, более читаемый:

 while read line; do printf '%s\n' "$line" cat "$line" done <locationfile.txt >finalfile 

Обратите внимание, что для этого требуется, чтобы все пути в файле locationfile.txt не содержали \ в них.

Хотя наличие \ в именах путей очень необычно, было бы безопаснее делать

 while read -r line; do printf '%s\n' "$line" cat "$line" done <locationfile.txt >finalfile 

… который не имеет одинаковых ограничений.

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

 while read -r line; do if [[ -f "$line" ]]; then printf '%s\n' "$line" cat "$line" else printf 'Warning: "%s" does not exist\n' "$line" >&2 fi done <locationfile.txt >finalfile 

«Не существует» означает «по крайней мере, не обычный файл».

Если вы хотите также "" , как своего рода маркер содержимого конца файла, просто введите его после cat :

 while read -r line; do if [[ -f "$line" ]]; then printf '%s\n' "$line" cat "$line" echo '""' else printf 'Warning: "%s" does not exist\n' "$line" >&2 fi done <locationfile.txt >finalfile 

И, наконец, дайте вещи самодокументируемым именам:

 while read -r file_path; do if [[ -f "$file_path" ]]; then printf '%s\n' "$file_path" cat "$file_path" echo '""' else printf 'Warning: "%s" does not exist\n' "$file_path" >&2 fi done <file_paths.txt >files_concat_with_paths.txt 
 while read file; do ( echo "$file"; cat "$file"; echo '"""' ) >> /path/to/outputfile done < /path/to/filelist 

Вот вариант, если у вас есть GNU awk, который вообще избегает оболочек оболочки:

 xargs -d '\n' -a locationfile.txt gawk 'BEGINFILE{print FILENAME} 1' > newfile 

или с GNU sed:

 xargs -d '\n' -a locationfile.txt sed -s '1F' > newfile 

Если вам не нужен точный формат имен файлов, вы можете использовать этот трюк с head :

 xargs -d '\n' -a locationfile.txt head -vn -0 > newfile 

( -n -0 говорит head чтобы выводить все строки, кроме первого 0, то есть всех строк).

Другой подход Perl:

 $ perl -le 'do{print $_,`cat $_`,"\"\"";} for <>' locationfile.txt text text text "" text text text "" text text text "" 

Это использует немного магии Perl и может потребоваться объяснение. -l удаляет завершающие символы новой строки из каждой строки ввода и добавляет новую строку для каждого вызова print . -e – как вы даете скрипт perl .

Теперь <> – это содержимое входного файла, разбитого на массив. Итак, do {foo} for <> будет запускать foo в каждой строке входного файла. Внутри этого цикла для каждой строки ввода назначается специальная переменная $_ . Синтаксис `command` запускает command в оболочке по умолчанию (системный вызов) и возвращает ее выход. Таким образом, cat $_ будет cat каждое имя файла в файле locationfile.txt .

В целом, print $_,`cat $_`,"\"\"" будет печатать имя файла (в настоящее время в $_ ), результат cat (содержимое файла), а затем "" (но нам нужно убежать те, так \"\" ).

Другими словами, этот скрипт означает «прочитайте каждую строку ввода, распечатайте ее, cat файл, который он содержит, и распечатайте "" после каждого файла.

Вы можете просто добавить echo "$line" в ваш цикл:

 cat locationfile.txt | while read line; do echo "$line" && cat "$line"; done 

AWK с помощью функции system() . Мы составляем командную строку через sprintf и передаем ее system()

 $ awk '{print $0; cmd=sprintf("cat \"%s\"",$0);system(cmd); print "\"\""}' filenames.txt /home/xieerqi/input1.txt Hello, I am input file #1 And this is second line of the text "" /home/xieerqi/input2.txt And I am input file #2 Roses are red, violets are blue AWK is awesome, Python is too "" /etc/resolv.conf # Dynamic resolv.conf(5) file for glibc resolver(3) generated by resolvconf(8) # DO NOT EDIT THIS FILE BY HAND -- YOUR CHANGES WILL BE OVERWRITTEN nameserver 127.0.1.1 "" 

И подход Perl, но с открывающим файлом в коде:

 $ perl -ne 'chomp; open($fh,$_) or die;print "$_\n";while($line = <$fh>){ print $line; print "\"\"\n" if eof}' filenames> /home/xieerqi/input1.txt Hello, I am input file #1 And this is second line of the text "" /home/xieerqi/input2.txt And I am input file #2 Roses are red, violets are blue AWK is awesome, Python is too "" /etc/resolv.conf # Dynamic resolv.conf(5) file for glibc resolver(3) generated by resolvconf(8) # DO NOT EDIT THIS FILE BY HAND -- YOUR CHANGES WILL BE OVERWRITTEN nameserver 127.0.1.1 "" 
  • Найти все слова, начинающиеся с Q
  • Какие символы мне нужно избегать при использовании sed в сценарии sh?
  • удаление строки из файла с помощью grep или sed, но количество строк все равно одинаково
  • Замените строку в нескольких файлах, используя find и sed
  • Удалить символ между двумя известными строками
  • как добавить дополнительный символ после поиска слова
  • Как использовать sed, как заменить строку, содержащую шаблон, содержимым из другого файла?
  • удалять только определенные текстовые вхождения из строки с помощью sed
  • Работа с столбцами - awk и sed
  • Vim: присоедините линии, заменив ^ M
  • совпадение шаблона N раз
  • Linux и Unix - лучшая ОС в мире.