1

Я читаю пару книг по bash-скриптингу и пытаюсь понять правильную цитату и использование IFS . Возможно, кто-то может помочь мне с небольшим примером, включающим имена файлов с кавычками. Делая это из командной строки, это работает для правильной распечатки имен файлов, даже если они содержат пробелы:

set - *
for i in "$@"; do echo $i; done

Это не работает, так как оно разбивается на пробелы:

set - `find . -name "*"`
for i in "$@"; do echo $i; done

И не делает:

IFS=$'\0' set - `find . -name "*" -print0`
for i in "$@"; do echo $i; done

И при этом комбинация, которая использует IFS=$'\n' и -print . Почему все это терпит неудачу?

Следующее также не выполняется, но в этом случае оно выдает ошибку («bash: синтаксическая ошибка рядом с неожиданным токеном« do »»). Зачем?

IFS=$'\n' for i in `find . -name "*" -type f`; do echo $i; done 

но это работает (обратите внимание на «;»):

IFS=$'\n'; for i in `find . -name "*" -type f`; do echo $i; done 

и это терпит неудачу, потому что имена файлов вообще не разделяются (цикл for только один раз):

IFS=''; for i in `find . -name "*" -type f -print0`; do echo -e "$i\n"; done

Итак, еще раз, почему первые и третьи там терпят неудачу?

Наконец, я прав, полагая, что при установке IFS '' совпадает с $'\0'? (Я попробовал оба в этом непосредственно предыдущем примере.) Если так, то почему мне, очевидно, нужен $'\n' а не просто \n?

* Bash - это версия 4.3.42(1) в Ubuntu Gnome 16.04.

1 ответ1

0

Две вещи, которые я изучил при отладке команд bash: Одна) Если она не работает так, как вы думаете, следует, выведите команды echo/printf, чтобы убедиться, что они отображают так, как вы думаете. 2) Вручную запустите команды, которые есть в ваших командах, чтобы проверить, правильно ли они выполняются (если только это не потенциально разрушительные команды, такие как: rm, dd, chmod 777 и т.д.).

Как или что именно вы пытаетесь достичь? Похоже, моя команда отлично работает с этой командой, поэтому вам нужно объяснить, что вы хотите от нее сделать. У вас есть пробелы в именах файлов, которые вызывают проблемы с вашей командой? Пока вы освобождаете пространство от переменной IFS, она, вероятно, будет работать так, как вы хотите: IFS=$'\n\t' . Опция -print0 основном удаляет все разделители строк, поэтому все, что вы хотите от этих команд, вообще не имеет разделителей, если в файлах нет пробелов в именах. Для вашего второго набора вопросов:

IFS=$'\n' for i in `find . -name "*" -type f`; do echo $i; done 

Эта команда не выполняется должным образом, потому что bash читает это так:

IFS=$'\n' for i in `find . -name "*" -type f`
do echo $i
done

Первая строка устанавливает IFS в: $'\n' for i in . После этого следующая строка читается как: do echo $i , что не работает, так как команде do требуется какой-то цикл, чтобы быть предшествующей командой. Следующая работает, потому что точка с запятой сообщает bash, что конец команды достигнут так:

IFS=$'\n'
for i in `find . -name "*" -type f`
do echo $i
done 

Наконец, я прав, полагая, что при установке IFS '' совпадает с $ '\0'? (Я попробовал оба в этом непосредственно предыдущем примере.) Если так, то почему мне, очевидно, нужен $ '\n', а не просто \n?

Да, в первой части '' и '\0' считаются NULL, поэтому они в основном одинаковы. Это связано с тем, что bash интерпретирует $'' как строку ANSI C. И вам нужно заключить в кавычки \n, чтобы bash интерпретировал ее как строку C, чтобы в IFS помещался символ новой строки.
Вы можете прочитать больше об этом здесь.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .