Concordo plenamente com @ilkkachu aqui.
Mas o FWIW, para poder usar o comando read
como parte da condição for
, com ksh93
(de onde vem essa sintaxe for ((...))
), você poderia usar disciplinas:
function read.get {
IFS= read -r line
.sh.value=$(($? == 0))
}
for ((i = 0; read; i++)) {
printf '%5d: %s\n' "$i" "$line"
}
Definimos a disciplina get
da variável $read
para que, quando expandida, o comando read
seja executado e $read
seja expandido para 1 se read
for bem-sucedida ou 0
caso contrário.
Ou uma variante usando tipos :
typeset -T read_t=(
typeset value
function get {
IFS= read -r _.value
((.sh.value = $? == 0))
}
)
read_t line
for ((i = 0; line; i++)) {
printf '%5d: %s\n' "$i" "${line.value}"
}
Em que o tipo read_t
é um tipo de objeto que, quando expandido, lê uma linha em theobject.value
e expande para 1 se o read
tiver êxito ou 0 caso contrário.
Ou a forma ${ ...; }
de substituição de comandos:
for ((i = 0; ${ IFS= read -r line; echo "$(($? == 0))";}; i++)) {
printf '%5d: %s\n' "$i" "$line"
}
Com zsh
, sequestrando o diretório nomeado dinâmico recurso :
set -o extendedglob
handle_-read:var()
case $1:$2 in
(d:-read:[a-zA-Z_][a-zA-Z0-9_]#)
IFS= read -r ${2#*:} && reply=('' $#2);;
(*) false;;
esac
zsh_directory_name_functions+=(handle_-read:var)
for ((i = 0; ${#${(D):--read:line}} == 3; i++)) {
printf '%5d: %s\n' "$i" "$line"
}
(não que eu recomendaria fazer isso).
Essa é a única maneira pela qual eu sei onde você pode ter um comando executado como parte de expressões aritméticas não em um subshell.
A substituição normal de comandos ( $(...)
ou '...'
) também pode ser usada para executar comandos em uma expressão aritmética, mas é feita em um subshell, então algo como:
for ((i = 0; $(IFS= read -r line; echo "$((!$?))"); i++)) {
printf '%5d: %s\n' "$i" "$line"
}
Embora seja uma sintaxe válida para bash
, não seria possível definir a variável $line
fora da subshell.
Com zsh
, você pode fazer algo como:
for ((i = 0; ${${line::=$(IFS= read -re)}+$?} == 0; i++)) {
printf '%5d: %s\n' "$i" "$line"
}
Embora isso seja ineficiente, uma vez que seria forçado um subshell para cada linha e alimentaria a linha através de um tubo extra.
bash
não possui o operador de expansão de parâmetro de atribuição ${var::=value}
incondicional e sua capacidade de aninhar expansões de parâmetro é muito limitada. Ele tem o operador ${var=value}
Bourne (atribua se previamente não configurado), e há alguns operadores que permitem o aninhamento como ${foo#${bar}}
, então você poderia fazer algo como:
unset line
for ((i = 0; 0*${?#"x${line='IFS= read -r && printf %s "$REPLY"'}"}+$? == 0; i++)); do
printf '%5d: %s\n' "$i" "$line"
unset line
done
(tendo aqui que trabalhar em torno de dois erros de bash
) .