Вы очень близко. Вы можете делать что хотите с помощью
while read line; do pushd "$line"; done < <(find "$(pwd)" -type d)
Проблема с вашей командой в том, что pushd
, как и cd
, должно быть выполнено в основном (родительском )процессе, чтобы быть полезным, и (с некоторыми вариациями в зависимости от того, как настроена ваша система ), команды в конвейере выполняются в подпроцессах (дочерних процессах ). < <(cmd)
волшебным образом дает вам трубку без предоставления вам трубопровода.
Для этого требуется, чтобы вы использовали bash (или, может быть, один из других продвинутых снарядов? ), поскольку POSIX не поддерживает <(cmd)
.
Подход xargs
, к сожалению, был обречен на провал, потому что pushd
(, как и cd
), является встроенной командой оболочки (т. е. не существует программы с именем pushd
), и xargs
требует внешней исполняемой программы. Вы можете получить вывод, что (почти )выглядит правильно с помощью этой команды:
$ find "$(pwd)" -type d | xargs -i sh -c 'pushd "$1"' sh
~/foo ~/foo
~/foo/bar1 ~/foo
~/foo/bar2 ~/foo
~/foo/bar3 ~/foo
но это выполняет оболочку как внешнюю программу, и делать это (независимо )для каждого каталога. Это немного ближе:
$ find "$(pwd)" -type d | xargs sh -c 'for line do pushd "$line"; done' sh
~/foo ~/foo
~/foo/bar1 ~/foo ~/foo
~/foo/bar2 ~/foo/bar1 ~/foo ~/foo
~/foo/bar3 ~/foo/bar2 ~/foo/bar1 ~/foo ~/foo
выполнение одного процесса оболочки, и сказать ему перебрать все каталоги. Как вы видете, эта техника аналогична вашей второй попытке (и моему ответу ), и результат такой же, как и во второй попытке — вы получаете новый процесс оболочки, который вызывает pushd
четыре раза, и заканчивается стеком каталогов, который имеет пять уровней глубины (двойной подсчет начального каталога )— но этот новый процесс оболочки находится в подпроцессе, и к тому времени, когда вы увидите следующее приглашение оболочки, этот процесс оболочки уже завершен.
Для справки: эта команда чем-то похожа на ответ, который я дал пару лет назад . Стефан Шазела обсуждает конструкция команды sh -c long_complex_shell_command sh
здесь и здесь .
Вы можете дополнить файл несколькими пустыми строками, чтобы в нем было как минимум 4 строки:
{ cat file; echo; echo; echo; } | sed -e '4i pattern'
Если вы хотите впоследствии обрезать завершающие пустые строки, вы можете передать это в:
| sed -n 'H; ${g; s/^\n//; s/\n\+$//; p}'
или
| tac | awk '/./{p=1}p' | tac
Или добавить только минимальное количество пустых строк:
{ cat file; for ((i=$(wc -l <file); i<3; i++)); do echo; done; } | sed '3a pattern'
Обратите внимание, что программа sed была изменена на добавление после строки 3 вместо вставки перед строкой 4.
Проверьте, достаточно ли строк file
с помощьюwc -l
(подсчета строк ).
Отображать предупреждение, если в файле недостаточно строк.
[ $(cat file | wc -l) -ge 4 ] && sed -i '4s pattern' file || echo "not enough lines"
while [ $(wc -l <file) -lt 4 ] ; do
echo >> file
done
sed -i '4i pattern' file