Создание файлов с использованием скрипта bash с двумя или более аргументами в другом файле - PullRequest
0 голосов
/ 11 января 2020

Я пытаюсь создать файлы, используя сценарий bash с двумя аргументами в другом файле.

Пример:

Мой bash файл сценария = myscript.bash
Мой исходный файл с аргументами = masterfile.txt

Вот что находится внутри masterfile.txt файла:


object1
record1

object2
record2

object4
record4

object3
record3

object5
record5


Теперь, когда я запускаю myscript. bash файл с использованием bash myscript.bash, он должен создавать папки и файлы с содержимым файлов на основе masterfile.txt, которое читается следующим образом:

... / object1 / object1.txt

Line1_Name: Dummy_Name1
Line2_Name: record1
Line2_Name: Dummy_Name2

... / object2 / object2.txt

Line1_Name: Dummy_Name1
Line2_Name: record2
Line3_Name: Dummy_Name2

... / object4 / object4.txt

Line1_Name : Dummy_Name1 * 1 056 * Line2_Name: record4
Line3_Name: Dummy_Name2

... / object3 / object3.txt

Line1_Name: Dummy_Name1
Line2_Name: record3
Line3_Name: Dummy_Name2

... / object5 / object5.txt

Line1_Name: Dummy_Name1
Line2_Name: record5
Line3_Name: Dummy_Name2

Может кто-нибудь помочь, пожалуйста? Это требует опыта в bash сценариях с несколькими аргументами, которых мне не хватает. Я пробовал для каждого l oop, что я застрял, потому что есть два аргумента. Я использовал следующие сайты в качестве справочной информации при составлении сценария, который не работает: (.

https://www.cyberciti.biz/faq/bash-loop-over-file/
https://www.geeksforgeeks.org/awk-command-unixlinux-examples/

1 Ответ

1 голос
/ 11 января 2020

Если я понимаю, что вы пытаетесь сделать, это действительно не так сложно, и у вас есть только 3 переменные (1) имя файла для чтения из masterfile.txt, (2) переменная для хранения каждой строки и ( 3) переменная для хранения нового имени выходного файла из строки, прочитанной перед прочтением "objectX".

Сам сценарий прост.

Вы задаете имя файла на основе первого аргумента как скрипт (или по умолчанию masterfile.txt). Очистите переменную ofile (имя выходного файла) и затем l oop чтение строк.

Если строка начинается с object, создайте каталог и сохраните строку как ofile (основание имя выходного файла). Если строка начинается с record, напечатайте 3 строки и еще раз ноль ofile, например,

#!/bin/bash

fname="${1:-masterfile.txt}"    ## filename [masterfile.txt (default)] 

[ -s "$fname" ] || {    ## validate file exists and is non-empty
    printf "error: %s empty or doesn't exist.\n" "$fname" >&2
    exit 1
}

ofile=      ## set outfile variable empty

## read each line in file, handle non-POSIX eof
while read -r line || [ -n "$line" ]; do
    if [[ $line =~ ^object ]]; then     ## if line starts with "object"
        mkdir -p "$line" || {           ## create/validate directory
            printf "error: failed to create %s.\n" "$line" >&2
            exit 1
        }
        ofile="$line"                   ## set outfile name to line
    ## otherwise, if line starts with "record" and outfile name not-empty
    elif [[ $line =~ ^record ]] && [ -n "$ofile" ]; then
        ## output your 3 lines
        printf "Line1_Name: Dummy_Name1\nLine2_Name: %s\nLine3_name: Dummy_Name2\n" \
            "$line" > "${ofile}/${ofile}.txt"
        ofile=  ## set outfile empty again
    fi
done < "$fname"

Содержимое каталога перед запуском сценария

Перед при запуске сценария каталог содержит:

$ tree
.
├── masterfile.txt
└── myscript.sh

0 directories, 2 files

Пример использования сценария

Запуск сценария:

$ bash myscript.sh masterfile.txt

Содержимое каталога После запуска сценария

После этого каталог содержит:

$ tree
.
├── masterfile.txt
├── myscript.sh
├── object1
│   └── object1.txt
├── object2
│   └── object2.txt
├── object3
│   └── object3.txt
├── object4
│   └── object4.txt
└── object5
    └── object5.txt

Содержимое выходного файла

Проверка object1.txt и object5.txt , у вас будет:

$ cat object1/object1.txt
Line1_Name: Dummy_Name1
Line2_Name: record1
Line3_name: Dummy_Name2

$ cat object5/object5.txt
Line1_Name: Dummy_Name1
Line2_Name: record5
Line3_name: Dummy_Name2

Посмотрите вещи и дайте мне знать, если у вас есть дополнительные вопросы. Существует несколько способов приблизиться к этому. awk была бы хорошей альтернативой.

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

Практически то же самое с использованием awk будет немного более эффективным. Ниже выполнено то же самое, что и myscript.sh выше. Единственное изменение заключается в том, что создание каталога было отложено до тех пор, пока не встретится строка recordX. Команда system() используется для создания каталога со строкой, хранящейся в scmd, которая "mkdir -p " объединяется со строкой objectX, например,

awk -v ofile="" '
    /^object/{ ofile=$0 }
    /^record/ && length(ofile) {
        scmd = "mkdir -p " ofile
        system(scmd)
        printf "Line1_Name: Dummy_Name1\nLine2_Name: %s\nLine3_name: Dummy_Name2\n", $0 > ofile"/"ofile".txt"
        ofile=""
    }
' masterfile.txt

Редактировать На основе разъяснения вопроса

Если objectX и recordX могут быть чем угодно, и вы используете пары строк, разделенные пустой строкой, для задания имени и содержимого каталога / имя файла и Line2..., требуется очень мало изменений. В приведенном выше сценарии тесты для object и record предоставили дополнительные проверки содержимого, но не являются обязательными для сценария.

Для устранения проверок objectX и recordX и полагаться только на новую строку, вам нужно только добавить дополнительную проверку вверху, чтобы проверить, была ли прочитанная строка пустой, например:

## read each line in file, handle non-POSIX eof
while read -r line || [ -n "$line" ]; do
    [ -z "$line" ] && continue;         ## empty line, skip, get next
    ...

Теперь вы можете удалить зависимость от любого содержимого masterfile.txt и просто используйте структуру файла. Например:

#!/bin/bash

fname="${1:-masterfile.txt}"    ## filename [masterfile.txt (default)] 

[ -s "$fname" ] || {    ## validate file exists and is non-empty
    printf "error: %s empty or doesn't exist.\n" "$fname" >&2
    exit 1
}

ofile=      ## set outfile variable empty

## read each line in file, handle non-POSIX eof
while read -r line || [ -n "$line" ]; do
    [ -z "$line" ] && continue;         ## empty line, skip, get next
    if [[ -z "$ofile" ]]; then          ## output file not set
        mkdir -p "$line" || {           ## create/validate directory
            printf "error: failed to create %s.\n" "$line" >&2
            exit 1
        }
        ofile="$line"                   ## set outfile name to line
    ## otherwise, if outfile name not-empty
    elif [ -n "$ofile" ]; then
        ## output your 3 lines
        printf "Line1_Name: Dummy_Name1\nLine2_Name: %s\nLine3_name: Dummy_Name2\n" \
            "$line" > "${ofile}/${ofile}.txt"
        ofile=  ## set outfile empty again
    fi
done < "$fname"

(создание файла / каталога такое же)

Обновлено awk Решение

Аналогично, awk решение может быть обновлено, чтобы работать на основе пар линий также. Здесь переменная ofile используется для хранения выходного имени файла и используется в качестве флага, чтобы определить, следует ли создать каталог и записать текущую строку. Встроенная переменная NF (количество полей) используется для проверки / пропуска пустой строки:

awk -v ofile="" '
    NF && ofile=="" { ofile=$0; next }
    NF && ofile!="" {
        scmd = "mkdir -p " ofile
        system(scmd)
        printf "Line1_Name: Dummy_Name1\nLine2_Name: %s\nLine3_name: Dummy_Name2\n", $0 > ofile"/"ofile".txt"
        ofile=""
    }
' masterfile.txt

(вывод такой же - вы можете просто скопировать и вставить среднюю мышь на командная строка в том же каталоге с masterfile.txt для проверки)

Попробуйте обновления и дайте мне знать, если у вас есть дополнительные вопросы.

...