Если я понимаю, что вы пытаетесь сделать, это действительно не так сложно, и у вас есть только 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
для проверки)
Попробуйте обновления и дайте мне знать, если у вас есть дополнительные вопросы.