Замена команды in for loop не работает

Я хочу сохранить все файлы, не заканчивающиеся на .bat

Я пытался

 for f in $(ls | egrep -v .bat); do echo $f; done 

а также

 for f in $(eval ls | egrep -v .bat); do echo $f; done 

Но оба подхода дают одинаковый результат, поскольку они печатают все. В то время как ls | egrep -v .bat ls | egrep -v .bat и eval ls | egrep -v .bat eval ls | egrep -v .bat работа сама по себе, если используется отдельно от цикла for .

РЕДАКТИРОВАТЬ

Интересно видеть, что если я -v флаг -v , цикл выполняет все, что нужно, и перечисляет все файлы, заканчивающиеся на .bat .


Не стесняйтесь редактировать заголовок вопроса, так как я не был уверен, в чем проблема.

Я использую GNU bash, version 4.1.10(4)-release (i686-pc-cygwin).


ПРИМЕР

 $ ls -l | egrep -v ".bat" total 60K -rwx------+ 1 SYSTEM SYSTEM 5.3K Jun 6 20:31 fsc* -rwx------+ 1 SYSTEM SYSTEM 5.3K Jun 6 20:31 scala* -rwx------+ 1 SYSTEM SYSTEM 5.3K Jun 6 20:31 scalac* -rwx------+ 1 SYSTEM SYSTEM 5.3K Jun 6 20:31 scaladoc* -rwx------+ 1 SYSTEM SYSTEM 5.3K Jun 6 20:31 scalap* 

Команда работает, но не в цикле for.

 $ for f in $(ls | egrep -v .bat); do echo $f; done fsc fsc.bat scala scala.bat scalac scalac.bat scaladoc scaladoc.bat scalap scalap.bat scalac scalac.bat scaladoc scaladoc.bat scalap scalap.bat 

DEBUG $ set -x

 mike@pc /cygdrive/c/Program Files (x86)/scala/bin $ for f in $(ls | egrep -v .bat); do echo $f; done ++ ls -hF --color=tty ++ egrep --color=auto -v .bat + for f in '$(ls | egrep -v .bat)' + echo fsc fsc + for f in '$(ls | egrep -v .bat)' + echo fsc.bat fsc.bat // and so on 

  • ls | Работа grep не работает с ls --color
  • Список только файлов, имеющих определенный символ в позиции
  • Как wc -l `ls` дает фактическое количество строк?
  • Невозможно перечислить каталог изнутри, только извне
  • Попросите команду ls вести себя по-разному в зависимости от количества записей
  • Установите ls-списки на основе регулярных выражений вместо globbing
  • Можно ли перечислить только определенные подкаталоги?
  • Человеко-читаемый вывод ls в AIX?
  • 3 Solutions collect form web for “Замена команды in for loop не работает”

    В вашем коде несколько ошибок:

    Использование замены без кавычек ( $(...) ) без установки $IFS

    Выделение разворота без кавычек – это оператор split + glob. По умолчанию используется разделение на пространство, вкладку и новую строку. Здесь вы хотите разделить только на новую строку, поэтому вам нужно установить IFS, так как иначе это означает, что не будет работать должным образом, если имена файлов содержат пробелы или символы табуляции

    Использование подменю без кавычек без set -f .

    Выделение разворота без кавычек – это оператор split + glob. Здесь вы не хотите глотания, то есть расширение подстановочных знаков, таких как scala* в список совпадающих файлов. Если вы не хотите, чтобы оболочка делала глобусы, вы должны отключить ее с помощью set -f

    ls aliased to ls -F

    Вышеупомянутый вопрос усугубляется тем фактом, что вы перешли к ls -F . Что добавляет / в каталоги и * в исполняемые файлы. Итак, как правило, поскольку scala является исполняемым, ls -F выводит scala* , а в качестве шаблона глобуса он расширяется до всех имен файлов, начинающихся с scala что объясняет, почему это похоже на то, что egrep -v не фильтрует файлы.

    Предполагая, что имена файлов не содержат символов новой строки

    newline является действительным символом, как любой в имени файла. Поэтому синтаксический анализ вывода ls обычно не работает . Например, вывод ls в каталоге, который содержит файлы a и b такой же, как в каталоге, который содержит один файл с именем a\nb .

    Выше egrep будет фильтровать строки имен файлов, а не имена файлов

    Использование egrep вместо grep -E

    egrep устарел. grep -E является стандартным эквивалентом.

    Не убежать . регулярный оператор.

    Выше вы использовали egrep для включения расширенных регулярных выражений, но вы не используете какой-либо расширенный RE-специфический оператор. Единственный оператор RE, который вы используете . чтобы соответствовать любому персонажу, хотя похоже, что это не то, что вы намеревались. Таким образом, вы могли бы использовать grep -F здесь. Или используйте grep -v '\.bat' .

    Не привязывать регулярное выражение к концу строки

    egrep .bat будет соответствовать любой строке, содержащей любой символ, за которым следует bat , поэтому это регулярное выражение означает все, что содержит bat не в первой позиции. Это должен был быть grep -v '\.bat$' .

    Оставляя $f unquoted

    Выход из функции без кавычек – это оператор split + glob. Там вы не хотите ни одного, поэтому $f следует указывать ( "$f" ).

    Использовать echo

    echo расширяет escape-последовательности ANSI C в своих аргументах и ​​/ или обрабатывает строки типа -n или -e специально в зависимости от реализации echo (и / или среды).

    Вместо этого используйте printf .

    Поэтому лучшее решение:

     for f in *; do case $f in (*.bat);; (*) printf '%s\n' "$f" esac done 

    Хотя, если в текущем каталоге нет не скрытого файла, это все равно будет выводиться * . Вы можете обойти это в zsh , изменив * на *(N) или в bash , запустив shopt -s nullglob .

    Вы не должны использовать ls для разбора файлов таким образом.

    Сначала установите extglob globstar через shopt -s extglob globstar затем

     for f in !(*.bat) do printf '%s\n' "$f" done 

    Использование find

     find . -type f ! -name '*.bat' 

    Используйте оператор отрицания для более безопасного обращения с файлами.

    В вашем цикле for ничего нет:

     $ for f in $(ls | egrep -v .bat); do echo $f; done 

    Вот мой вывод для приведенной выше команды:

     $ for f in $(ls | egrep -v .bat); do echo $f; done fsc scala scalac scaladoc scalap 

    Возможное исправление

    Одним из предложений было бы привести аргумент egrep , например:

     $ for f in $(ls | egrep -v '.bat'); do echo $f; done 

    Также взгляните на вики Bash Pitfalls для других потенциальных проблем при написании сценариев в Bash, таких как это. В частности, это звучит как самая правдоподобная причина, по которой вы сталкиваетесь с этой проблемой. Проверьте, не содержат ли какие-либо из ваших файлов пробелы.

    отладка

    Еще одна вещь, которую нужно попробовать – включить подробную отладку вашей команды bash, прежде чем запускать ее, чтобы вы могли видеть, что происходит за кулисами.

    Это позволяет отлаживать:

     $ set -x 

    Затем запустите команду:

     $ for f in $(ls | egrep -v .bat); do echo $f; done ++ ls --color=auto ++ egrep --color=auto -v .bat + for f in '$(ls | egrep -v .bat)' + echo fsc fsc + for f in '$(ls | egrep -v .bat)' + echo scala scala + for f in '$(ls | egrep -v .bat)' + echo scalac scalac + for f in '$(ls | egrep -v .bat)' + echo scaladoc scaladoc + for f in '$(ls | egrep -v .bat)' + echo scalap scalap 

    Затем отключите его:

     $ set +x 

    Проблема с Cygwin?

    Учитывая, что примеры хорошо работают на ряде родных систем Linux, проблема, скорее всего, связана с тем, что она связана с Cygwin и / или конкретными версиями bash и egrep . Я бы обратил особое внимание на разделитель полей в Bash, $IFS чтобы узнать, существует ли проблема между различными разделителями строк в Windows ( 0x0d,0x0a ) и Unix ( 0x0a ).

    У меня нет установки Cygwin, поэтому у меня нет метода доказательства этой гипотезы.

    Linux и Unix - лучшая ОС в мире.