Захватить файл и отдельные столбцы и добавить sth с помощью массивов

Я хочу управлять моим /etc/passwd и добавлять имена для каждого столбца.

Я хочу читать из массива...

Я попробовал следующее bash:

#!/bin/bash

FILE="/etc/passwd"
arr=( $(awk < $FILE -F: '{print $1 $5 $6 $7}') )

for Username Realname Homedir Loginshell in "${arr[@]}"; do
 result=$(printf 'Username: %s Realname: %s Homedir: %s Loginshell: %s' "$Username" "$Realname" "$Homedir" "Loginshell")
 echo "$result"
done

Но есть ошибка:

./u.sh: line 6: syntax error near unexpected token 'Realname'
./u.sh: line 6: 'for Username Realname Homedir Loginshell in "${arr[@]}"; do'

Второй вопрос:

Как я могу читать $FILE в качестве аргумента в таких скриптах... потому что при смене сценария вроде:

#!/bin/bash

if [ "$#" -ne "1" ]; then
 echo "Usage: 'basename $0' <input-file>"
 exit 1
fi

arr=( $(awk < $1 -F: '{print $1 $2 $6 $7}') )

for Username Realname Homedir Loginshell in "${arr[@]}"; do
 result=$(printf 'Username: %s Realname: %s Homedir: %s Loginshell: %s' "$Username" "$Realname" "$Homedir" "Loginshell")
 echo "$result"
done
</input-file>

Это сбой...

благодаря

2 ответа

Этот подход позволяет избежать awk но используя bash IFS для разделения полей в FILE:

FILE="/etc/passwd"
while IFS=: read Username pass uid gid Realname Homedir Loginshell; do
 result=$(printf 'Username: %s Realname: %s Homedir: %s Loginshell: %s' "$Username" "$Realname" "$Homedir" "$Loginshell")
 echo "$result"
done <"$FILE"

Чтобы указать имя файла в качестве аргумента (согласно вопросу 2):

if [ "$#" -ne "1" ]; then
 echo "Usage: 'basename $0' <input-file>"
 exit 1
fi
FILE=$1

while IFS=: read Username pass uid gid Realname Homedir Loginshell; do
 result=$(printf 'Username: %s Realname: %s Homedir: %s Loginshell: %s' "$Username" "$Realname" "$Homedir" "$Loginshell")
 echo "$result"
done <"$FILE"
</input-file>

Если вы хотите использовать массивы, то:

#!/bin/bash
if [ "$#" -ne "1" ]; then
 echo "Usage: 'basename $0' <input-file>"
 exit 1
fi
FILE=$1

#declare -a fields
IFS=:
while read line; do
 fields=($line)
 result=$(printf 'Username: %s Realname: %s Homedir: %s Loginshell: %s' "${fields[0]}" "${fields[4]}" "${fields[5]}" "${fields[6]}")
 echo "$result"
done <"$FILE"
</input-file>

Вышеприведенная информация читает /etc/passwd одной строке за раз. Если IFS установлен в двоеточие, каждая строка затем преобразуется в массив с использованием fields=($line). Чтобы избежать сюрпризов, вы можете сбросить IFS до значения по умолчанию перед выполнением какого-либо кода bash который зависит от стандартных правил разделения слова bash.

Дополнительно:

Вот попытка довольно печатать вывод:

#!/bin/bash
if [ "$#" -ne "1" ]; then
 echo "Usage: 'basename $0' <input-file>"
 exit 1
fi
FILE=$1

{
echo "========:========:=======:=========="
echo "Username:Realname:Homedir:Loginshell"
echo "========:========:=======:=========="

IFS=:
while read line; do
 fields=($line)
 echo "${fields[0]}:${fields[4]}:${fields[5]}:${fields[6]}"
done < "$FILE"
} | column -nts:
</input-file>

По умолчанию column разделяет поля по пробелам. Однако поле вывода реального имени может содержать пробелы. Таким образом, используется -s: так, чтобы column использовал двоеточие -s, обработанные поля на входе. Чтобы гарантировать, что заголовки, выстроенные в соответствии с полями данных, как заголовки, так и данные передаются в один и тот же column.


Используйте его так:

while read Username Realname Homedir Loginshell; do
 result=$(printf "Username: %s Realname: %s Homedir: %s Loginshell: %s" "$Username" "$Realname" "$Homedir" "Loginshell")
 echo "$result"
done < <(awk -F: '{print $1 $2 $6 $7}' /etc/passwd)

EDIT: вы можете просто использовать awk:

if (($# == 0)); then
 echo "Usage: 'basename $0' <input-file>"
 exit 1
fi
FILENAME="$1"

awk -F: '{printf "Username: %s Realname: %s Homedir: %s Loginshell: %s\n",
 $1, $2, $6, $7}' "$FILENAME"
</input-file>

licensed under cc by-sa 3.0 with attribution.