POSIX совместимый способ работать со списком имен файлов возможно с пробелом

Можно сделать это со сценарием оболочки.

Чистый sh - это будет работать даже над оболочками Bourne предPOSIX:

n=1;
max=50;
while [ "$n" -le "$max" ]; do
  mkdir "s$n"
  n=`expr "$n" + 1`;
done

Если Вы хотите создать высокое количество каталогов, можно сделать сценарий быстрее путем сокращения его до единственного вызова mkdir а также использование оболочки builtins для тестирования и арифметики. Как это:

n=1
max=50
set -- # this sets $@ [the argv array] to an empty list.

while [ "$n" -le "$max" ]; do
    set -- "$@" "s$n" # this adds s$n to the end of $@
    n=$(( $n + 1 ));
done 

mkdir "$@"

Zsh, ksh93 или удар делают это намного легче, но я должен указать, что это не создается в mkdir и может не работать в других оболочках. Для больших случаев это может также быть затронуто пределами на число или общий размер аргументов, которые могут быть переданы команде.

mkdir s{1..50}
14
29.11.2013, 01:12
2 ответа

Оболочки POSIX имеют один массив: позиционные параметры ($1, $2, и т.д., коллективно отнесенный в как "$@").

set -- 'foo/target/a.jar' 'foo/target/b.jar' 'bar/target/b.jar' 'bar/target/lol whitespace.jar'
set -- "$@" '/another/one at the end.jar'
…
for jar do
  dostuffwith "$jar"
done

Это неудобно, потому что существует только один, и это уничтожает любое другое использование позиционных параметров. Позиционные параметры локальны для функции, которая является иногда благословением и иногда проклятием.

Если Ваши имена файлов, как гарантируют, не будут содержать новые строки, можно использовать новые строки в качестве разделителя. Когда Вы разворачиваете переменную, сначала выключаете globbing с set -f и набор список полевых символов разделения IFS содержать только новую строку.

INPUT="foo/target/a.jar
foo/target/b.jar
bar/target/b.jar
bar/target/lol whitespace.jar"
…
set -f; IFS='
'                           # turn off variable value expansion except for splitting at newlines
for jar in $INPUT; do
  set +f; unset IFS
  dostuffwith "$jar"        # restore globbing and field splitting at all whitespace
done
set +f; unset IFS           # do it again in case $INPUT was empty

С объектами в Вашем списке, разделенном новыми строками, можно использовать много команд обработки текста полезно в особенности sort.

Не забудьте всегда помещать двойные кавычки вокруг подстановок переменных, кроме тех случаев, когда Вы явно хотите, чтобы полевое разделение произошло (а также globbing, если Вы не выключили это).

8
27.01.2020, 19:51
  • 1
    Хороший ответ и объяснение. Я собираюсь отметить это, как принято, потому что это делает оригинал sort | uniq ступите работа, как предназначено. вздох –  Eero Aaltonen 09.12.2013, 11:52

Начиная с Вашего $INPUT переменная использует новые строки в качестве разделителей, я собираюсь предположить, что Ваши файлы не будут иметь новых строк на имена. По сути, да, существует простой способ выполнить итерации по файлам и сохранить пробел.

Идея состоит в том, чтобы использовать read встроенная оболочка. Обычно read разделит на любом пробеле, и таким образом, пробелы повредят его. Но можно установить IFS=$'\n' и это вместо этого разделит на новых строках только. Таким образом, можно выполнить итерации по каждой строке в списке.

Вот самое маленькое решение, которое я мог предложить:

INPUT="foo/target/a.jar
foo/target/b.jar
bar/target/b.jar
bar/target/lol whitespace.jar"

dostuffwith() {
    echo "$1"
}

echo "$INPUT" | awk -F/ '{if (!seen[$NF]++) print }' | \
while IFS=$'\n' read file; do
  dostuffwith "$file"
done

В основном это отправляет "$INPUT" в awk который дедуплицирует на основе имени файла (оно разделяет на / и затем печатает строку, если последний объект не был замечен прежде). Затем, после того как awk генерировал список путей к файлам, мы используем while read выполнить итерации через список.

5
27.01.2020, 19:51
  • 1
    checkbashisms bar.sh возможный bashism в bar.sh строке 14 (<<<здесь представляют в виде строки) –  Eero Aaltonen 28.11.2013, 14:12
  • 2
    @EeroAaltonen, Измененный это для не использования herestring. Отметьте хотя это с этим изменением, while цикл, и таким образом dostuffwith выполняется в подоболочке. Таким образом, любые переменные или изменения, внесенные в рабочую оболочку, будут потеряны, когда цикл завершится. Единственная альтернатива должна использовать полный heredoc, который не настолько неприятен, но я думал, что это будет предпочтительно. –  Patrick 29.11.2013, 00:28
  • 3
    я присуждаю очки, базировался больше на удобочитаемости, чем небольшие размеры. Это, конечно, работает и уже +1 для этого. –  Eero Aaltonen 29.11.2013, 11:21
  • 4
    IFS="\n" разделения на обратной косой черте и n символах. Но в read file, нет никакого разделения. IFS="\n" все еще полезно в этом, это удаляет символы пробела из $IFS, который иначе был бы разделен вначале и конец входа. Для чтения строки канонический синтаксис IFS= read -r line, хотя IFS=anything read -r line (если что-либо не содержит пробелы), будет работать также. –  Stéphane Chazelas 18.11.2014, 10:31
  • 5
    ой. Не уверенный, как я управлял тем. Фиксированный. чувак –  Patrick 18.11.2014, 15:21

Теги

Похожие вопросы