При циклическом обходе каталогов, особенно если у них странные имена, не повторяйте вывод ls
. В общем, передача путей между программами должна выполняться с большой осторожностью, поскольку имена файлов Unix могут содержать любые символы, кроме /
и нулевого символа(\0
).
Вместо
for dirname in./*/; do
printf 'Directory name is "%s"\n' "$dirname"
done
Последнее /
в шаблоне ./*/
расширяет шаблон только до каталогов. При этом переменная dirname
получит такие значения, как ./some directory name/
. Я включил ./
в начале паттерна, но вы можете удалить его, если хотите. Просто имейте в виду, что если у вас есть каталоги, в именах которых есть тире(-
)в качестве первого символа, вам позже придется использовать, например,.mv -- "$dirname" "$newname"
(с --
), чтобы mv
не интерпретировал тире в имени как параметр командной строки. При ./
в начале $dirname
--
не требуется.
Очень особенно важно заключать расширения переменных в кавычки, так как в противном случае оболочка будет выполнять разбиение на слова и подстановку имен файлов в значениях.
Связанные:
Учитывая модификацию вашего образца ввода:
$ cat input
Host Status Expires Days
----------------------------------------------- ------------ ------------ ----
FILE:certs/dnscert1.crt Valid Aug 1, 2020 7
FILE:certs/dnscert2.crt Invalid Aug 4, 2021 359
FILE:certs/dnscert3.crt Valid Aug 4, 2021 359
Затем, если я применю следующую команду awk
, я получу:
$ awk 'NR > 2 { print $1 "," $2 ",\"" $3, $4, $5 "\"," $6}' input
FILE:certs/dnscert1.crt,Valid,"Aug 1, 2020",7
FILE:certs/dnscert2.crt,Invalid,"Aug 4, 2021",359
FILE:certs/dnscert3.crt,Valid,"Aug 4, 2021",359
Предполагается, что поле даты всегда состоит из 3 токенов :месяца, дня и года.
NR > 2
пропускает первые две строки :заголовка и разделителя. Остальные просто печатают поля с запятыми между ними, стараясь указать поля даты.
Предполагая, что сценарий оболочки предоставляет данные с пробелами для разметки, вы можете использовать awk для преобразования в разделенную вкладку -. Excel откроет вкладку -файл с разделителями (, возможно, жалуясь на несоответствие формата ), и при необходимости позволит пользователю сохранить как xlsx.
$my_script | awk -v OFS='\t' '{$1=$1}1' > myexcel.xls
В котором используется трюк, чтобы принудительно использовать OFS, а затем печатать. Или менее загадочный:
$my_script | '{print $1 "\t" $2 "\t" $3 "\t" $4}' > myexcel.xls
Существуют модули для ваших любимых языков сценариев, которые будут создавать «настоящий» файл xlsx (, который представляет собой просто заархивированный каталог XML ), но это более сложно. Если вам просто нужно что-то, что пользователи могут щелкнуть и открыть в Excel, отлично подойдет вкладка -, разделенная расширением xls..
Поля сами содержат пробелы, как и поле даты, поэтому нам нужно разработать другую стратегию.
Используя заголовок (, предполагая, что в именах полей нет пробелов, )получите ширину каждого поля и вставьте ее в FIELDWIDTHS, встроенную -в переменную awk, во втором проходе по входному файлу.
$ fw=$(< file \
awk -v FPAT='[^[:space:]]+([[:space:]]+|$)' ' NR>1{exit}
{for (i=1; i<=NF; i++) $i=length($i)}1')
$ awk \
-v q=\" -v OFS=, \
-v FIELDWIDTHS="$fw" \
'
function trim(a, l, t) {
l = "^[[:space:]]+"
t = "[[:space:]]+$"
re = l "|" t
gsub(re, "", a)
return a
}
function quote(a, r, nondigit) {
r = "[^[:digit:]]"
nondigit = a ~ r
return nondigit ? q a q : a
}
NR==2{next}
{
for (i=1; i<=NF; i++) {
t = $i
gsub(/"/, "\\&", t)
t = trim(t)
$i = quote(t)
}
}1' file
"Host","Status","Expires","Days"
"FILE:certs/dnscert.crt","Valid","Aug 4, 2021",359