В оболочке, поддерживающей <()
(bash, ksh, zsh), вы можете преобразовать
$ cmd1 | cmd2
в
$ cmd2 < <(cmd1)
Эти две формы должны быть эквивалентны с точки зрения конвейеризации. (Однако, я думаю, есть некоторые незначительные различия в том, как эти две формы обрабатывают такие вещи, как группа процессов и сигналы).
Для лучшего редактирования командной строки я рекомендую вам изучить возможности вашей оболочки для этого.
Например, в bash есть set -o vi
, который позволяет вам использовать vi-подобные ярлыки или переключаться в vim
напрямую для более эффективного редактирования команды. По умолчанию set -o emacs
использует ярлыки emacs (чтобы узнать о них больше, найдите в man bash
readline (/readline
)).
Попробуйте это (встроенные комментарии):
#!/bin/bash
set -f # Prevent e.g. *.txt from being expanded here
dir=$1 # Get the target directory and
shift # remove from list of args
cmd="find $dir -type f"
while (( "$#" )) # While there are more arguments left
do
cmd="$cmd -not -name $1" # add to not match
shift # and remove from list of arguments
done
cmd="$cmd -exec rm -i {} ;" # finally execute rm on the remaining matches
echo $cmd # Print the final find command
$cmd # And execute it
Я добавил -i
к rm
, чтобы он спрашивал перед удалением каждого файла. Но это можно, конечно, подкорректировать.
Тот же механизм, что иlaenkeio , ответ , но более минималистичный. нет -переменная POSIX функция оболочки:
rmexcept(){ find "$1" $(shift; printf " -not -name %s" ${@}) -exec rm '{}' \; ;}
Команда оболочки printf
выполняет основную работу вместо for
или while
петля.
Используя оболочку bash
, shift
можно заменить параметром расширение:
rmexcept(){ find "$1" $(printf " -not -name %s" ${@:2}) -exec rm '{}' \; ;}
Обратите внимание, что ни одна из функций не завершит задание, если результирующие команды find
или rm
длиннее числа, возвращаемого getconf ARG_MAX
. См.:Командная строка Bash и ограничение ввода .