Действия
rm
при работе с несколькими файлами или каталогами не являются атомарными. В данном случае это имеет значение, потому что rm -r
выполняет поиск файлов и каталогов снизу вверх -, удаляя их из листьев в корень запрошенного пути. Это делается с помощью unlink
и rmdir
до тех пор, пока ничего не останется, а затем rmdir
является конечным каталогом.
Эти действия происходят последовательно, поэтому, если до выдачи rmdir
создается больше файлов, вы получаете ответENOTEMPTY
("Каталог не пуст" ).
Более чем вероятно, что ваш скрипт или другой процесс, работающий в системе, создает вещи одновременно с rm -rf
.Возможно, вам следует подумать о:
rm -rf
, если она не удалась и возвращает ENOTEMPTY (, хотя тогда другое приложение может завершиться ошибкой, поскольку каталог был удален из-под него)Вы можете найти другое приложение, которое создает файлы, используя что-то вроде fanotify
или скрипт eBPF, например opensnoop
из BCC . inotify
также может быть полезным, но, к сожалению, он не включает процесс создания файлов в свои выходные данные.
Другая возможность заключается в том, что удаление файла не удалось, но это может быть замаскировано -f
. Попробуйте запустить без -f
, чтобы увидеть, что может быть ошибкой в этом случае.
Сsed + paste
$ sed 's/.*/"&"/' databases.txt
"Wp_new"
"Frontend DB"
"DB_EXT"
$ sed 's/.*/"&"/' databases.txt | paste -sd' ' -
"Wp_new" "Frontend DB" "DB_EXT"
Или простоpaste
(вежливостьhttps://unix.stackexchange.com/a/593240)
$ <databases.txt paste -d '"' /dev/null - /dev/null | paste -sd' ' -
"Wp_new" "Frontend DB" "DB_EXT"
Если ввод содержит пустые строки, их следует игнорировать:
$ cat ip.txt
Wp_new
Frontend DB
DB_EXT
$ sed -n 's/..*/"&"/p' ip.txt | paste -sd' ' -
"Wp_new" "Frontend DB" "DB_EXT"
чтобы ваш вывод был текстовым файлом POSIX:
awk '
function output(sep, record){ printf "\"%s\"%s", record, sep }
prev{ output(FS, prev) } { prev=$0 } END{ output(ORS, prev) }' infile
$ awk '{printf "%s\"%s\"", sep, $0; sep=OFS} END{print ""}' file
"Wp_new" "Frontend DB" "DB_EXT"
Существует несколько способов достижения результата с помощью sed
. Вот два решения:
$ sed 's/^/"/;s/$/"/' infile | sed ':a;{N;s/\n/ /;ba}'
"Wp_new" "Frontend DB" "DB_EXT"
или
$ sed 's/.*/"&"/' infile | sed ':a;{N;s/\n/ /;ba}'
"Wp_new" "Frontend DB" "DB_EXT"
Сначала в начало и конец каждой текстовой строки добавляются двойные кавычки, затем текстовые строки объединяются.
Вот еще одно sed
решение. Неизбежно, он имеет некоторое совпадение с ответами fpmurphy и Sundeep .
{ sed 's/.*/"&"/; 1!s/^/ /' databases.txt | tr -d '\n'; echo;}
Как отмечает Сандип, вы можете переместить < databases.txt
в начало команды если вы особенно предпочитаете видеть спецификацию ввода в этой позиции (, а не в середине команды ). И вы можете заменить echo
на printf '\n'
— хотя, следуя комментариям Эда Мортона , echo
могли бы лучше генерировать соответствующие конец -символа строки -(s )в чем-то другом, кроме чистого контекста Unix/Linux (например, гибрид Windows/GNU ).
Мне нравится использовать tr(1)
для преобразования многострочных строк в однострочные, а затем работать с ними с помощью sed(1)
, сначала вставляя конечную и начальную кавычки, а затем заменяя все «внутренние» точки с запятой, т.е.:
$ cat databases.txt | tr '\n' ';' | sed 's/;$/"\n/; s/^/"/; s/;/" "/g'
"Wp_new" "Frontend DB" "DB_EXT"
Конечно, вы можете выбрать любой другой символ, кроме ;
, если он не содержится в самом вводе.
Хотя об этом должно быть легко рассуждать, это не обязательно переносимо и определенно не POSIX, как правильно указал @g -man -говорит -восстановить -monica. Проблема заключается в том, что sed необходимо прочитать всю строку ---здесь весь файл ---, в то время как POSIX требует только 8192-байтовых строк(1). Кроме того, ввод для sed должен быть файлом (, т.е. заканчиваться новой строкой 2).
Я хочу оставить этот трюк здесь, так как он по-прежнему удобен, если вышеуказанные ограничения не применяются, однако я хочу подчеркнуть, что его не следует использовать как часть скрипта:)
Это можно сделать в некотором sed с помощью:
$ sed ':a;N;$!ba;s/\n/" "/g;s/.*/"&"/' databases.txt
"Wp_new" "Frontend DB" "" "DB_EXT" "" "empty"
Или, если вам не нравятся названия веток и веток:
$ sed -n '/^$/!{
${H;x;s/\n/" "/g;s/.*/"&"/;p;d;}
$!{H;1h}
}' databases.txt
"Wp_new" "Frontend DB" "DB_EXT" "empty"
Но оба загружают весь файл в память, что может занять много времени для длинных файлов.
С некоторой помощью пасты sed мог читать строки один -в -в -раз:
$ sed 's/.*/"&"/' databases.txt | paste -sd ' '
"Wp_new" "Frontend DB" "" "DB_EXT" "" "empty"
Нет необходимости в обычном ' -' для вставки, так как он по умолчанию читается со стандартного ввода, если не указан ФАЙЛ.
Это также можно сделать в awk с явными значениями:
$ awk 'BEGIN{dq="\""; sp=""} {
printf "%s%s%s%s", sp, dq, $0,dq; sp=" "
}END{print ""}' databases.txt
"Wp_new" "Frontend DB" "DB_EXT"
Все ответы хороши, я думаю, это зависит от того, какой результат вы ожидаете. Если вам нужен необработанный текст строки без дополнительных символов или если необходимо добавить некоторые, я попробовал это, и это работает очень хорошо для меня:
Просто свернуть текст:
cat yourFile | paste -sd' ' -
>item1 item2 item3
Элемент объемного звучания с двойными -кавычками:
sed -n 's/..*/"&",/p' yourFile | paste -sd' ' -
>"item1", "item2", "item2",
awk 'ORS=" "{print "\""$0"\""}' filename
выход
"Wp_new" "Frontend DB" "DB_EXT"