Совершенно другой подход :Создайте группу students
, дайте каждому учащемуся свою учетную запись с членством в группе в students
. Имейте сценарий, который восстанавливает заданный домашний каталог из шаблона в известное хорошее состояние, возможно, удаляя все лишние файлы точек. Расскажите учащимся об этом сценарии.
Если у вас несколько компьютеров, централизуйте этот подход (управление пользователями на одном центральном сервере )и используйте центральный файловый сервер для домашних каталогов учащихся, чтобы каждый учащийся получал один и тот же домашний каталог на любой машине..
Вместе с правильными (базовымиchmod
)разрешениями везде это гарантирует, что каждый учащийся сможет сеять хаос только в своем собственном домашнем каталоге и может восстановить его, когда он сломается, возможно, потеряв свои собственные настройки в этом процессе., так что в следующий раз они будут осторожнее.
Кстати, это очень стандартная настройка для многих пользователей кластера машин.
$ cat tst.awk
NR == 1 {
for (i=1; i<=NF; i++) {
if ($i != "-") {
f[++numOutFlds] = i
}
}
}
{
for (i=1; i<=numOutFlds; i++) {
printf "%s%s", $(f[i]), (i<numOutFlds ? OFS : ORS)
}
}
$ awk -f tst.awk file
M A A
- G -
M - -
awk
неявно перебирает входные записи (строки )и файлы, но не поля, которые вы должны делать явно. В вашем случае вам нужно перебрать поля в первой строке (заголовка ), чтобы решить, какие столбцы включить, а затем перебрать поля в каждой строке заголовка (и не заголовке ). чтобы включить нужные столбцы в эту строку.
Вам не ясно, хотите ли вы искать поля заголовка, которые равны(строке )" -" или могут иметь ее как(sub )строка . Я также предполагаю, что у вас есть (все )отдельные вкладки в качестве разделителей полей, а не несколько пробелов, которые были бы более утомительными (и их нельзя отличить визуально от вашего поста ).
awk -F"\t" 'NR==1{for(i=1;i<=NF;i++)s[i]=$i!="-"} {x="";for(i=1;i<=NF;i++)if(s[i])x=x FS $i;print substr(x,2)}'
# for _matches_ "-" instead of _equals_ "-" change $i!="-" to $i!~/-/
# note if a nonheader line has more fields than the header did,
# all extra fields are nonselected (as if their header field was/matched -)
# or (re)use the flags for both what to include _and_ when to terminate the line
awk -F"\t" 'NR==1{t=RS;for(i=NF;i;i--)if(s[i]=($i!="-"?t:""))t=FS} {for(i=1;i<=NF;i++)if(s[i])printf "%s%s",$i,s[i]}'
# some people may consider this too clever
Вариация ответа Эда Мортона , который запоминает, каких полей нет -
в первой строке по их номеру поля, а затем повторно -формирует каждую запись во входных данных в соответствии с сохраненным индексы в массиве out
перед печатью новой записи:
FNR == 1 {
for (i = 1; i <= NF; ++i)
if ($i != "-") out[++nf] = i
}
{
for (i = 1; i <= nf; ++i)
a[i] = $(out[i])
$0 = ""
for (i = 1; i <= nf; ++i)
$i = a[i]
print
}
Здесь я немного пожертвовал эффективностью ради удобочитаемости, реконструируя запись в отдельном цикле, а не печатая требуемые поля в одном цикле во втором блоке.
Тестирование:
$ awk -f script.awk file
M A A
- G -
M - -
Запуск с вкладками в качестве разделителя полей вывода:
$ awk -v OFS='\t' -f script.awk file
M A A
- G -
M - -
Слишком длинный -вкладыш, зависящий от того, что входные данные разделены табуляцией -:
$ cut -f "$(awk -v OFS=',' '{ nf=split($0,a); $0=""; for (i=1; i<=nf; ++i) if (a[i]!="-") $(++NF)=i; print; exit }' file)" file
M A A
- G -
M - -
Здесь используется awk
для вывода номеров полей , которые не находятся -
в первой строке, в виде списка, разделенного запятыми -. Затем этот список передается в cut -f
, который фактически выводит данные из файла. Обратите внимание, что имя файла (здесь простоfile
)дается дважды в командной строке, один раз для awk
, а затем еще раз для cut
.
Использование Perl.
Для первой строки постройте массив @A
индексов, для которых поле не является тире.
Затем для всех строк, включая первую, выведите только те поля из @F
, индексы которых находятся в @A
.
$ perl -lane '$, = "\t";
$. == 1 and @A = grep $F[$_] ne "-", 0..$#F;
print @F[@A];
' file
Выход:
M A A
- G -
M - -
Мы можем сделать это, используя sed
, хотя код GNU sed в расширенном режиме регулярных выражений, но это просто лекарство от backslashitis
.
Метод заключается в создании карты из первой строки. Поля, которые нужно сохранить, обозначаются как x, другие — как тире. Сохраните эту карту в трюме.
Затем для всех строк добавьте эту карту и поместите маркер в BOL.
В цикле мы продолжаем удалять начальное поле текущей строки, если видим \n -И перемещаем маркер на следующее поле.
Зацикливание завершается, когда этот маркер сталкивается с новой строкой между текущей строкой и удерживаемым пробелом, (из-за команды G ).
$ sed -Ee '
1{
h
y/-/\n/
s/\S+/x/g;s/[[:blank:]]+//g
y/\n/-/
x
}
G;s/^/\n/
:a
s/\n(\S+\s*)(.*\n)x/\1\n\2/
s/\n(\S+\s*)(.*\n)-/\n\2/
/\n\n/!ba
s/\s+$//
' file
Результаты
M A A
- G -
M - -