Как преобразовать переменную массива bash в строку, разделенную символами новой строки?
Я хочу записать переменную массива bash в файл, с каждым элементом в новой строке. Я мог бы сделать это с помощью цикла for, но есть ли другой (более чистый) способ соединить элементы с \n
?
6 ответов
Вот способ, который использует расширение параметра bash и его IFS
специальная переменная.
$ System=('s1' 's2' 's3' 's4 4 4')
$ ( IFS=$'\n'; echo "${System[*]}" )
Мы используем подоболочку, чтобы избежать перезаписи значения IFS
в нынешних условиях. В этой подоболочке мы затем изменим значение IFS
так что первый символ является новой строкой (используя $'...'
цитирую). Наконец, мы используем расширение параметра, чтобы напечатать содержимое массива как одно слово; каждый элемент отделен первым знаком IFS
,
Для захвата в переменную:
$ var=$( IFS=$'\n'; echo "${System[*]}" )
Если ваш bash достаточно новый (4.2 или более поздний), вы можете (и должны) по-прежнему использовать printf
с -v
опция:
$ printf -v var "%s\n" "${System[@]}"
В любом случае, вы можете не захотеть заключительный перевод строки в var
, Чтобы удалить это:
$ var=${var%?} # Remove the final character of var
Ты можешь использовать printf
напечатать каждый элемент массива в отдельной строке:
$ System=('s1' 's2' 's3' 's4 4 4')
$ printf "%s\n" "${System[@]}"
s1
s2
s3
s4 4 4
awk -v sep='\n' 'BEGIN{ORS=OFS="";for(i=1;i<ARGC;i++){print ARGV[i],ARGC-i-1?sep:""}}' "${arr[@]}"
или же
perl -le 'print join "\n",@ARGV' "${arr[@]}"
или же
python -c 'import sys;print "\n".join(sys.argv[1:])' "${arr[@]}"
или же
sh -c 'IFS=$'\''\n'\'';echo "$*"' '' "${arr[@]}"
или же
lua <(echo 'print(table.concat(arg,"\n"))') "${arr[@]}"
или же
tclsh <(echo 'puts [join $argv "\n"]') "${arr[@]}"
или же
php -r 'echo implode("\n",array_slice($argv,1));' -- "${arr[@]}"
или же
ruby -e 'puts ARGV.join("\n")' "${arr[@]}"
это все, что я могу напомнить до сих пор.
Приведенные выше решения в значительной степени таковы, но исходный вопрос требует вывода в файл:
$ a=(a b c d e)
$ ( IFS=$'\n'; echo "${a[*]}" ) > /tmp/file
$ cat /tmp/file
a
b
c
d
e
$
Примечания: 1) 'echo' предоставляет последний символ новой строки 2) Если этот файл будет просто снова прочитан bash, тогда объявить -p может быть желаемой сериализацией.
Использование для:
for each in "${alpha[@]}"
do
echo "$each"
done
Использование истории; обратите внимание, что это не удастся, если ваши значения содержат !
:
history -p "${alpha[@]}"
Использование базового имени; обратите внимание, что это не удастся, если ваши значения содержат /
:
basename -a "${alpha[@]}"
Использование shuf; обратите внимание, что результаты могут быть не в порядке:
shuf -e "${alpha[@]}"
Мой дубль, использующий только встроенные функции Bash, без мутаций IFS
:
# $1 separator
# $2… strings
join_strings () {
declare separator="$1";
declare -a args=("${@:2}");
declare result;
printf -v result '%s' "${args[@]/#/$separator}";
printf '%s' "${result:${#separator}}"
}
пример
$ join_strings $'\n' "a b c" "d e f" "g h i"
a b c
d e f
g h i
Вы также можете использовать любой разделитель:
$ join_strings '===' "a b c" "d e f" "g h i"
a b c===d e f===g h i
Вот мое впечатление от joinArray:
function joinArray() {
local delimiter="${1}"
local output="${2}"
for param in ${@:3}; do
output="${output}${delimiter}${param}"
done
echo "${output}"
}
Как было сказано ранее, следующее:
$ printf -v var "%s\n" "${System[@]}"
работает, если вы конвертируете в строку, но вам нужно иметь дело с одной пустой строкой в конце. Я считаю, что вы можете избежать этого, используя вместо этого подстановку команд, поэтому
$ var=$(printf '%\n' "${System[@]}")
должно работать нормально. Просто не забудьте указать var, чтобы добиться желаемого эффекта!
printf
кажется наиболее эффективным подходом для создания строки с разделителями из массива:
# create a delimited string; note that printf doesn't put the trailing delimiter
# need to save and restore IFS
# it is prudent to put the whole logic on a single line so as to minimize the risk of future code changes breaking the sequence of saving/restoring of IFS
oldIFS=$IFS; IFS=$'\n'; printf -v var "${arr[*]}"; IFS=$oldIFS
# print string to file; note that the newline is required in the format string because printf wouldn't put a trailing delimiter (which is a good thing)
printf '%s\n' "$var" > file
Еще более простой способ сделать это:
delim=$'\n'
printf -v var "%s$delim" "${arr[@]}" # create a delimited string
var="${var%$delim}" # remove the trailing delimiter
пример
delim=:
arr=(one two three)
printf -v var "%s$delim" "${arr[@]}" # yields one:two:three:
var="${var%$delim}" # yields one:two_three