Скрипты Bash и цитирование

Скрипты Bash и цитирование

Я читаю пару книг по скриптингу 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

Две вещи, которые я усвоил при отладке команд bash: во-первых, если что-то работает не так, как вы думаете, должно работать, выведите команды echo/printf, чтобы убедиться, что они отображаются так, как вы думаете. во-вторых, вручную запустите команды, которые есть в ваших командах, чтобы проверить, правильно ли они работают (если только это не потенциально разрушительные команды, такие как: 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.
Вы можете прочитать больше об этомздесь.

Связанный контент