скопируйте содержимое файла в другое место

#linux #bash #awk #copy

#linux #bash #awk #Копировать

Вопрос:

у меня есть текстовый файл, содержащий выходные результаты функции (строка пути и чуть ниже результатов), и я хочу скопировать только результаты, указанные ниже каждой строки пути, в файл, который упоминается в name= …. и хочу вставить в последний столбец файла

мои данные здесь сохраняются в list.txt

 <_io.TextIOWrapper name='/home/liu/datalist/20180603_190202_5.0_38_CD.txt' mode='r' encoding='UTF-8'>
0.9821305886510053
0.9822639336394542
0.9820650754926169
0.9826369946635649
0.983048680372995
<_io.TextIOWrapper name='/home/liu/datalist/20150603_190202_12.0_36_CD.txt' mode='r' encoding='UTF-8'>
0.984263067046808
0.9821305886510053
0.9822639336394542
0.9820650754926169
0.9826369946635649
0.983048680372995
<_io.TextIOWrapper name='/home/liu/datalist/20120603_190202_9.0_35_CD.txt' mode='r' encoding='UTF-8'>
0.984263067046808
0.982871209110385
0.9830143471771022
0.9860952410409616
0.9897257569597108
<_io.TextIOWrapper name='/home/liu/datalist/20100603_190202_125.0_36_CD.txt' mode='r' encoding='UTF-8'>
0.9860794488788789
0.9838808626335948
0.9829656043793615
0.9868238026934462
0.9972756725839034
0.9882482212913676
<_io.TextIOWrapper name='/home/liu/datalist/20240603_190202_265.0_36_CD.txt' mode='r' encoding='UTF-8'>
0.9856758910581078
0.9849158515561436
0.9838016078370099
0.9854127382758501
0.9880763165814402
  

я попробовал приведенный ниже код: не понял, как это сделать.Надеюсь, мне поможет какой-нибудь эксперт.Спасибо

 #!/bin/sh
for file in `list.txt`
cp cat|list.txt > name
  

Подробное объяснение:
предположим, мы возьмем 20180603_190202_5.0_38_CD.txt подайте на рассмотрение.Этот именованный файл уже присутствует в каталоге /home/liu/datalist и содержит файл типа

 1 2 3 4 5
5 6 7 8 9
3 4 5 6 7
3 4 5 6 7 
4 5 6 7 8
  

и я хочу, чтобы файл был таким, как показано ниже

 1 2 3 4 5 0.9821305886510053
5 6 7 8 9 0.9822639336394542
3 4 5 6 7 0.9820650754926169
3 4 5 6 7 0.9826369946635649
4 5 6 7 8 0.983048680372995
  

Ответ №1:

Другое решение с использованием ассоциативных массивов:

 #!/bin/bash

declare -A filetemp

while read -r line
do
    if [[ $line =~ "name='"(.*?.txt) ]]
    then
        name="${BASH_REMATCH[1]}"
        filetemp[$name]=$(mktemp)
    else
        [ -n "$name" ] amp;amp; echo "$line" >> "${filetemp[$name]}"
    fi
done < list.txt

for name in "${!filetemp[@]}"
do
    paste -d ' ' "$name" "${filetemp[$name]}" > "${name}.tmp"
    mv -f "${name}.tmp" "$name"
done
  

РЕДАКТИРОВАТЬ: забыл об этом, но на всякий случай было бы неплохо очистить временные файлы, созданные mktemp после того, как они больше не требуются:

 for name in "${!filetemp[@]}"
do
    tempfile="${filetemp[$name]}"
    paste -d ' ' "$name" "$tempfile" > "${name}.tmp"
    mv -f "${name}.tmp" "$name"
    rm -f "$tempfile"
done
  

РЕДАКТИРОВАТЬ 2: как указано @lucasgvarela, trap команда может быть более элегантным способом удаления временных файлов при срабатывании EXIT сигнала:

 trap 'rm -f "${filetemp[@]}"' EXIT

for name in "${!filetemp[@]}"
do
    paste -d ' ' "$name" "${filetemp[$name]}" > "${name}.tmp"
    mv -f "${name}.tmp" "$name"
done
  

Комментарии:

1. куда включить имя моего входного файла, чтобы протестировать код

2. Он должен находиться в вашем текущем рабочем каталоге ( cwd ), то есть в том же каталоге, из которого вы в данный момент выполняете скрипт, если вручную. Для хорошей оценки наилучшей практикой было бы использовать абсолютный путь вместо относительного пути, но я не знаю, где здесь находится файл (например, если файл находится внутри /root , перепишите done < list.txt в done < /root/list.txt ).

3. k … позвольте мне check….my исходные файлы содержат немного более длинный путь… таким образом, требуется ли что-то менять в коде

4. @Rfroes87 о вашей правке, что вы думаете о команде TRAP, разве это не хороший способ улучшить удаление этих файлов mktemp?

5. @Rfroes87 Я рад помочь, в этом прелесть человеческого бытия, мы каждый день узнаем что-то новое, кстати, ты сделал красивый код: D, я исправил / отредактировал свой прямо сейчас, старая версия была уродливой

Ответ №2:

РЕДАКТИРОВАТЬ: новый код, исправляющий старый уродливый код: D

Результат

 $ cat 20150603_190202_12.0_36_CD.txt 
1 2 3 4 5
5 6 7 8 9
3 4 5 6 7
3 4 5 6 7
4 5 6 7 8

$ cat 20180603_190202_5.0_38_CD.txt 
1 2 3 4 5
5 6 7 8 9
3 4 5 6 7
3 4 5 6 7
4 5 6 7 8

$ ./test.sh 

$ cat 20150603_190202_12.0_36_CD.txt 
1 2 3 4 5 0.984263067046808
5 6 7 8 9 0.9821305886510053
3 4 5 6 7 0.9822639336394542
3 4 5 6 7 0.9820650754926169
4 5 6 7 8 0.9826369946635649

$ cat 20180603_190202_5.0_38_CD.txt 
1 2 3 4 5 0.9821305886510053
5 6 7 8 9 0.9822639336394542
3 4 5 6 7 0.9820650754926169
3 4 5 6 7 0.9826369946635649
4 5 6 7 8 0.983048680372995
  

Код

 $ cat test.sh 
#!/bin/bash

cat list.txt | cut -d '/' -f5- | sed "s/' mode='r' encoding='UTF-8'>//" > new_list.txt

while read -r line
do
  if [[ "$line" =~ ".txt" ]]; then
    count=0
    filename="$line"
    touch "$filename"
  else
    count=$(($count 1))
    originalline=$(sed -n ${count}p "$filename")
    sed -i "0,/^$originalline$/s//$originalline $line/" "$filename"
  fi
done < "new_list.txt"

rm new_list.txt
  

Комментарии:

1. что на самом деле 5 в if [[ $count -eq 5 ]]; тогда… подскажите, пожалуйста

2. @anonymossi это был счетчик, но я все еще пытаюсь исправить этот код до лучшей версии, которая не зависит от счетчиков..

3. @anonymossi привет, теперь, пожалуйста, прочитайте еще раз код, он намного лучше, счетчик — это всего лишь один из способов узнать, в какой строке должна произойти замена. старый счетчик делал что-то совсем другое и ошибочное ….

4. Это интересная альтернатива; это позволяет избежать необходимости создания ассоциативного массива — который, насколько я знаю, зависит от declare команды bash — и выполнения 2 циклов, что может сделать его более оптимизированным, чем мой подход.