Intereting Posts
Как правильно настроить DNS. , , с концептуальной точки зрения Нет / proc / bus / usb directory Как работает опция монтирования _netdev в / etc / fstab? Обрежьте определенное поле и замените его в сценарии оболочки Unix Как использовать VPN и не VPN в одно и то же время? Каковы два файла head.S в источнике Linux? Linux Mint 18 не может подключиться к какой-либо сети Wi-Fi в zsh, как скрыть обратную косую черту в меню завершения Как ограничить некоторые команды для администратора в Linux (CentOS) Добавление пользовательских последовательностей ключевых слов Малый офисный сервер и UID-перевод Почему $ является символом по умолчанию для оболочки пользователя и # символом по умолчанию для корневой оболочки? Цвета не отображаются правильно в oh-my-zsh-темах Как я могу обновить сертификаты в своей системе, чтобы исправить ошибку wget: «Не удалось установить соединение SSL»? Debian Wheezy LXDE: Значки рабочего стола исчезают, как их восстановить?

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

У меня есть файл, содержащий местоположения разных файлов, называемых 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 "" 

Перед тем, как 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 ""