Як перетворити змінну масиву bash в рядок, розмежований новими рядками?


50

Я хочу виписати змінну масиву bash у файл із кожним елементом у новому рядку. Я міг би зробити це за допомогою циклу for, але чи є інший (чистіший) спосіб з'єднання елементів \n?

Відповіді:


59

Ось спосіб, який використовує розширення параметра bash та його IFSспеціальну змінну.

$ System=('s1' 's2' 's3' 's4 4 4')
$ ( IFS=$'\n'; echo "${System[*]}" )

Ми використовуємо нижню оболонку, щоб уникнути перезапису значення IFSв поточному середовищі. У цій підпакеті ми змінюємо значення IFSтак, щоб перший символ був новим рядком (використовуючи $'...'цитування). Нарешті, ми використовуємо розширення параметрів для друку вмісту масиву як одне слово; кожен елемент відокремлений першим характером IFS.

Для захоплення до змінної:

$ var=$( IFS=$'\n'; echo "${System[*]}" )

Якщо ваш Баш досить новий (4,2 або пізнішої версії), ви можете (і повинні) по- , як і раніше використовувати printfз -vопцією:

$ printf -v var "%s\n" "${System[@]}"

В будь-якому випадку ви, можливо, не хочете остаточного нового рядка в var. Щоб видалити його:

$ var=${var%?}    # Remove the final character of var

Дякую, чи є спосіб вивести це на змінну?
ACyclic

Оновлено, щоб показати, як перехопити до змінної.
чепнер

2
Чи не var=${var%?}замість цього повинен бути останній приклад ? Це не регулярний вираз, тому .відповідатиме лише символу періоду.
musiphil

Потрібні цитати ім'я змінної масиву:$ IFS=', ' $ echo ${VAR[*]} first second third $ echo "${VAR[*]}" first,second,third
Seff

28

Ви можете використовувати printfдля друку кожного елемента масиву у своєму власному рядку:

 $ System=('s1' 's2' 's3' 's4 4 4')
 $ printf "%s\n"  "${System[@]}"
s1
s2
s3
s4 4 4

7
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[@]}"

це все, про що я можу нагадати.


2

Вищезазначені рішення в значній мірі це, але оригінальне питання вимагає вихід у файл:

$ a=(a b c d e)
$ ( IFS=$'\n'; echo "${a[*]}" ) > /tmp/file
$ cat /tmp/file
a
b
c
d
e
$

Примітки: 1) "Відлуння" надає остаточний новий рядок. 2) Якщо цей файл просто буде прочитаний в bash ще раз, тоді оголосити -p може бути потрібною серіалізацією.


2

Використання для :

for each in "${alpha[@]}"
do
  echo "$each"
done

Використання історії ; зауважте, що це не вдасться, якщо ваші значення містять !:

history -p "${alpha[@]}"

Використання базового імені ; зауважте, що це не вдасться, якщо ваші значення містять /:

basename -a "${alpha[@]}"

Використання шуф ; зауважте, що результати можуть вийти не для того, щоб:

shuf -e "${alpha[@]}"

0

Моє прийняти , використовуючи лише вбудовані 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

-1

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

2
Downvoter, будь ласка, прокоментуйте, що тут не так.
кодовий ліс
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.