Объединение нескольких файлов из разных каталогов.

Использование GNUsed:

sed -i '$s/,$//' file

То есть в последней строке($)замените(s)запятую в конце строки(,$)ничем.

Изменение будет выполнено в месте -из-за флага -i.

Со стандартнымsed:

sed '$s/,$//' <file >file.new &&
mv file.new file

Примечание :Кто-то предложил изменить "в последней строке" на "последний в строке" (или что-то подобное ). Это не правильно. Когда $используется для указания адреса (строки, где применить команду редактирования ),тогда это относится к последней строке потока или файла. Это отличается от использования $в регулярном выражении.

1
29.04.2020, 17:12
3 ответа

Проблема с вашим подходом заключается в том, что повторяющиеся подстановочные знаки интерпретируются не (="расширенными" )"синхронизированным" способом, а заново и независимо для каждого появления в командной строке -. Следовательно, вам нужно будет работать с вложенными циклами оболочки.

Вы можете попробовать следующий сценарий оболочки. Обратите внимание, что он использует bashфункции (ваш вопрос не включал, какую оболочку вы используете)

#!/bin/bash

hdr=0   # initialize variable to keep track of whether the header is already printed

# loop over directories
for d in Chr*
do
    # extract trailing number from dir name by removing 'Chr' part (bash feature!)
    n="${d#Chr}"

    # loop over all files
    for f in "$d/"*".$n"
    do
       if (( hdr == 0 )) # if header wasn't printed yet, output entire file
       then
           cat "$f" > final_file
           hdr=1
       else              # otherwise, output file content starting with line 2
           tail -n +2 "$f" >> final_file
       fi
    done
done

Вы можете назвать сценарий concatenate.sh, сделать его исполняемым и запускать его из каталога, в котором расположены все ваши Chr{1..22}подкаталоги. final_fileтакже будет создан в этом каталоге.

Заметьте, я не мог проверить это очень далеко, но это не должно ничего разрушать...

1
19.03.2021, 02:19

Если вы хотите захватить все файлы во всех ваших подкаталогах Chr.*, вы можете использовать это

cat Chr*/* >final_file

Если вам нужно ограничить набор файлов в каждом подкаталоге, чтобы он соответствовал суффиксу имени этого каталога (, поэтому в Chr1мы рассматриваем только файлы, соответствующие *.1), вам понадобится цикл

shopt nullglob    # This is bash-specific
for i in {1..22}
do
    cat Chr$i/*.$i
done >final_file

Необязательный параметр shopt nullglobсообщает оболочке, что если подстановочный знак не может совпасть, его следует удалить, а не оставить буквальную звездочку.

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

first=yes
for i in {1..22}
do
    for f in Chr$i/*.$i
    do
        [[ -n "$first" ]] && head -n1 "$f" && first=
        cat "$f"
    done
done >final_file

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

for i in {1..22}
do
    cat Chr$i/*.$i
done |
    awk '$0 != header { print } header == "" { header = $0 }' >final_file
0
19.03.2021, 02:19

Вместо этого используйте оболочку zsh:

cat -- */Chr<1-22>/*.<1-22>(n) > final_file

В zsh<x-y>— это оператор подстановки, который соответствует диапазонам десятичных целых чисел, а квалификатор nglob переключает параметр numericglobsort, который приводит к числовой сортировке расширений подстановки.

Из другой оболочки вы можете сделать:

zsh -c 'cat -- */Chr<1-22>/*.<1-22>(n) > final_file'

Чтобы пропустить заголовок во всех файлах, кроме первого, и предполагая, что реализация GNU или busyboxtail(наиболее распространена в системах, использующих Linux в качестве ядра ), вы можете сделать:

(){
  cat < $1; shift; (($#)) && tail -qn +2 -- "$@"
} */Chr<1-22>/*.<1-22>(n) > final_file 
2
19.03.2021, 02:19

Теги

Похожие вопросы