Замена команды: разделение на новой строке, но не пространстве

Yudit является редактором, специально предназначенным для привыкания хорошо с “экзотическими” комбинациями языка и языка. Это включает усовершенствованную поддержку двунаправленного текста. На минус сторона, это иначе довольно примитивно для редактора.

Ответвление разработки Emacs (то, что в настоящее время известно как Emacs 24.0.50.x и в конечном счете будет Emacs 24.1), поддерживает двунаправленный текст. На Ubuntu попробуйте  пакет http://bit.ly/software-small emacs-снимка Установки emacs-снимка (поскольку это - снимок разработки, можно быть более обеспеченной перекомпиляцией более поздней версии).

30
10.10.2014, 13:49
6 ответов

Похож на канонический способ выполнить в этом bash что-то как

unset args
while IFS= read -r line; do 
    args+=("$line") 
done < file

cmd "${args[@]}"

или, если Ваша версия удара имеет mapfile:

mapfile -t args < filename
cmd "${args[@]}"

Единственная разница, которую я могу найти между mapfile и, в то время как - считал цикл по сравнению с остротой

(set -f; IFS=$'\n'; cmd $(<file))

это, первый преобразует пустую строку в пустой аргумент, в то время как острота проигнорирует пустую строку. В этом случае поведение остроты - то, что я предпочел бы так или иначе, так двойная премия на нем являющийся компактным.

Я использовал бы IFS=$'\n' cmd $(<file) но это не работает, потому что $(<file) интерпретируется для формирования командной строки прежде IFS=$'\n' вступает в силу.

Хотя это не работает в моем случае, я теперь узнал что много строк завершения поддержки инструментов с null (\000) вместо newline (\n) который действительно делает многое из этого легче при контакте с, скажем, именами файлов, которые являются общими источниками этих ситуаций:

find / -name '*.config' -print0 | xargs -0 md5

подает список полностью определенных имен файлов как аргументы md5 без любого globbing или интерполяции или что бы то ни было. Это приводит к невстроенному решению

tr "\n" "\000" <file | xargs -0 cmd

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

8
27.01.2020, 19:38
  • 1
    Используя cmd $(<file) значения, не заключая в кавычки (использование способности удара разделить слова) всегда являются опасной ставкой. Если какая-либо строка * это будет расширено оболочкой до списка файлов. –   25.07.2015, 00:51

Портативно:

set -f              # turn off globbing
IFS='
'                   # split at newlines only
cmd $(cat <file)
unset IFS
set +f

Или использование подоболочки для создания IFS и локальные изменения опции:

( set -f; IFS='
'; exec cmd $(cat <file) )

Оболочка выполняет полевое разделение и поколение имени файла на результате переменной или замены команды, которая не находится в двойных кавычках. Таким образом, необходимо выключить поколение имени файла с set -f, и настройте полевое разделение с IFS заставить только новые строки разделить поля.

Нет очень, чтобы быть полученным с конструкциями ksh или ударом. Можно сделать IFS локальный для функции, но нет set -f.

В ударе или ksh93, можно сохранить поля в массиве, если необходимо передать их нескольким командам. Необходимо управлять расширением в то время, когда Вы создаете массив. Затем "${a[@]}" расширяется до элементов массива, один на слово.

set -f; IFS=$'\n'
a=($(cat <file))
set +f; unset IFS
cmd "${a[@]}"
26
27.01.2020, 19:38

Можно сделать это с временным массивом.

Установка:

$ cat input
AAA
A B C
DE F
$ cat t.sh
#! /bin/bash
echo "$1"
echo "$2"
echo "$3"

Заполните массив:

$ IFS=$'\n'; set -f; foo=($(<input))

Используйте массив:

$ for a in "${foo[@]}" ; do echo "--" "$a" "--" ; done
-- AAA --
-- A B C --
-- DE F --

$ ./t.sh "${foo[@]}"
AAA
A B C
DE F

Не может выяснить способ сделать это без той временной переменной - если IFS изменение не важно для cmd, в этом случае:

$ IFS=$'\n'; set -f; cmd $(<input) 

должен сделать это.

10
27.01.2020, 19:38
  • 1
    IFS всегда получает меня перепутанный. IFS=$'\n' cmd $(<input) не работает. IFS=$'\n'; cmd $(<input); unset IFS действительно работает. Почему? Я предполагаю, что буду использовать (IFS=$'\n'; cmd $(<input)) –  Old Pro 28.05.2012, 02:27
  • 2
    @OldPro IFS=$'\n' cmd $(<input) не работает, потому что это только устанавливает IFS в среде cmd. $(<input) расширен для формирования команды, перед присвоением на IFS выполняется. –  Gilles 'SO- stop being evil' 28.05.2012, 03:17

Вы могли использовать встроенный удар mapfile считать файл в массив

mapfile -t foo < filename
cmd "${foo[@]}"

или, непротестированный, xargs мог бы сделать это

xargs cmd < filename
3
27.01.2020, 19:38
  • 1
    Из mapfile документации: "mapfile не является общей или портативной функцией оболочки". И действительно это не поддерживаемый в моей системе. xargs не помогает, также. –  Old Pro 28.05.2012, 01:36
  • 2
    Вам было бы нужно xargs -d или xargs -L –  James Youngman 28.05.2012, 01:48
  • 3
    @James, нет, у меня нет a -d опция и xargs -L 1 выполняет команду однажды на строку, но все еще разделяет args на пробеле. –  Old Pro 28.05.2012, 02:43
  • 4
    @OldPro, хорошо Вы действительно просили "способ сделать это с помощью, только колотят созданный-ins" вместо "общей или портативной функции оболочки". Если Ваша версия удара слишком стара, можно ли обновить его? –  glenn jackman 28.05.2012, 04:32
  • 5
    mapfile очень удобно для меня, поскольку это захватывает пустые строки как объекты массива, который IFS метод не делает. IFS рассматривает непрерывные новые строки как единственный разделитель... Спасибо за представление его, поскольку я не знал о команде (хотя, на основе входных данных OP и ожидаемой командной строки, это кажется им на самом деле, хочет проигнорировать пустые строки). –  Peter.O 28.05.2012, 08:02
old=$IFS
IFS='  #newline
'
array=`cat Submissions` #input the text in this variable
for...  #use parts of variable in the for loop
... 
done
IFS=$old

Лучший способ, который я смог найти. Просто работает.

0
27.01.2020, 19:38

Файл

Самый простой цикл (Portable )для разделения файла на символы новой строки::

#!/bin/sh
while read -r line; do            # get one line (\n) at a time.
    set -- "$@" "$line"           # store in the list of positional arguments.
done <infile                      # read from a file called infile.
printf '<%s>' "$@" ; echo         # print the results.

Что напечатает:

$./script
<AAA><A B C><DE F>

Да, по умолчанию IFS= пробелвкладкановая строка .

Почему это работает

  • IFS будет использоваться оболочкой для разделения ввода на несколько переменных. Поскольку существует только одна переменная, оболочка не выполняет разделения. Таким образом, изменение IFSне требуется.
  • Да, начальные и конечные пробелы/табуляции удаляются, но в данном случае это не проблема.
  • Нет, подстановка не выполняется, так как расширение не без кавычек . Таким образом, set -fне требуется.
  • Единственный используемый (или необходимый )массив — это массив -, подобный позиционным параметрам.
  • Параметр-r(raw )позволяет избежать удаления большей части обратной косой черты.

Это не будет работать, если требуется разделение и/или подстановка. В таких случаях требуется более сложная структура.

Если вам нужно (по-прежнему переносное )на:

  • Избегайте удаления начальных и конечных пробелов/табуляции, используйте:IFS= read -r line
  • Разбить строку на vars по некоторому символу, используйте:IFS=':' read -r a b c.

Разделить файл на какой-то другой символ (не переносимый, работает с ksh, bash, zsh):

IFS=':' read -d '+' -r a b c

Расширение

Конечно, заголовок вашего вопроса касается разделения выполнения команды на новые строки без разделения на пробелы.

Единственный способ получить разделение из оболочки — оставить расширение без кавычек:

echo $(< file)

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

  • Установите IFS только на новую строку , чтобы получить разбиение только на новую строку.
  • Отключить параметр оболочки с подстановкойset +f:

    установить +f ИФС=' ' cmd $ (< файл)

Конечно, это меняет значение IFS и подстановки для остальной части скрипта.

0
27.01.2020, 19:38

Теги

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