Sample Header Ad - 728x90

Unix & Linux Stack Exchange

Q&A for users of Linux, FreeBSD and other Unix-like operating systems

Latest Questions

3 votes
2 answers
108 views
Localising variables in /bin/sh functions
POSIX defines [shell functions](https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_09_05) as: ``` fname ( ) compound-command [io-redirect ...] ``` The [compound-command](https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_09_04) is further d...
POSIX defines [shell functions](https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_09_05) as:
fname ( ) compound-command [io-redirect ...]
The [compound-command](https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_09_04) is further defined as either:
( compound-list )
{ compound-list ; }
In particular POSIX notes for the first form that "_variable assignments and built-in commands that affect the environment shall not remain in effect after the list finishes._" I've noticed that the idiomatic structure with bash code seems to be to use a braced compound list with the local keyword: f1() { local arg1=$1 arg2=$2 p q # arg1, arg2, p, q are all local vars shift 2 … } In general, assuming the function doesn't modify global variables, we can simplify this to use the bracketed form that implicitly localises all its variables: f2() ( arg1=$1 arg2=$2 # all variables are implicitly local shift 2 … ) Aside from using local as an explicit declaration of local variables, is there any general reason to prefer the braced f1() { …; } construct, which seems to be more commonly used than f2() ( … )?
Chris Davies (126603 rep)
Jul 30, 2025, 04:18 PM • Last activity: Aug 1, 2025, 01:09 PM
27 votes
5 answers
15776 views
How to get current buffer's filename in emacs?
One of the main features I miss about Vim, is that it always saves the filename of the current file in the `%` buffer ([more info][1]). That allows launching commands easily like: ;; compile current file :! gcc % ;; source current file (useful when I'm editing .vimrc :source % ;; get the size of cur...
One of the main features I miss about Vim, is that it always saves the filename of the current file in the % buffer (more info ). That allows launching commands easily like: ;; compile current file :! gcc % ;; source current file (useful when I'm editing .vimrc :source % ;; get the size of current file :! du -sh % ;; etc, etc... I would like to have similar functionality under emacs (version 24, if that makes any difference), namely have an easy way to insert the name of the file opened in the current buffer. **Examples of what I want to do** *Here I describe some basic use cases as to explain better when I feel the need for such a shortcut* 1. Compile: When I enter M-x compile emacs asks me for a compile command. I would like to enter gcc (current-buffer) easily. 2. Load-file: When I'm editing my .emacs file, I would like to load it right away to test the changes. The way I do it is M-x load-file and then I always spell out the name . e m a c s. I would like to have a shortcut. 3. Launch outside processes: I gave du -sh as an example, only to illustrate that I want the shortcut to be also available when I execute shell commands with M-! **What I found so far** - This question here on U&L. The answers given are basically showing where to find the filename of a buffer so one can add it to the kill-ring. It's not exactly what I'm looking for, I don't want to have to manually kill the filename before I want to use it. (Also solutions described in both answers don't seem to work as smoothly in my emacs and require additional keystrokes making them a bit of a pain). ***EDIT**: A bit unrelated, by I found out why these solutions don't work. I have IDO enabled, for better or worse.* - The (current-buffer) function described in the manual does return the name of the file in the current buffer, but nowhere in the examples I gave above, am I evaluating elisp code. Is there a way to insert the result of the evaluation of this function in a (mini)buffer and binding this way to a shortcut? **Am I wrong to think this way?** I am currently learning to use emacs (it's been a few months actually) after years of using Vim. I want to avoid a predictable *using-emacs-in-a-Vim-way* trap. If you feel that what I'm asking for is not very *emacs-y*, and there should be a better (cleaner?) way to do it, please do mention it in your answers.
rahmu (20511 rep)
Aug 9, 2012, 09:30 AM • Last activity: Jul 18, 2025, 10:25 AM
0 votes
2 answers
222 views
How we can recursively expand inline functions and aliases inside function?
Nesting problem with duck typing: function f1 { echo $1; } #with argument function f2 { N=$((0+1)); f$N "fff"; } #with dynamic name Desired result: function f2 { { echo $1; } "fff"; } NB. sorry I revised the problemt to real codding issues. How to solve the issue?
Nesting problem with duck typing: function f1 { echo $1; } #with argument function f2 { N=$((0+1)); f$N "fff"; } #with dynamic name Desired result: function f2 { { echo $1; } "fff"; } NB. sorry I revised the problemt to real codding issues. How to solve the issue?
mr.tee (119 rep)
Jun 21, 2023, 09:26 AM • Last activity: Jul 9, 2025, 10:47 AM
49 votes
14 answers
40480 views
Executing a Bash Script Function with Sudo
I have a script that does a number of different things, most of which do not require any special privileges. However, one specific section, which I have contained within a function, needs root privileges. I don't wish to require the entire script to run as root, and I want to be able to call this fu...
I have a script that does a number of different things, most of which do not require any special privileges. However, one specific section, which I have contained within a function, needs root privileges. I don't wish to require the entire script to run as root, and I want to be able to call this function, with root privileges, from within the script. Prompting for a password if necessary isn't an issue since it is mostly interactive anyway. However, when I try to use sudo functionx, I get: sudo: functionx: command not found As I expected, export didn't make a difference. I'd like to be able to execute the function directly in the script rather than breaking it out and executing it as a separate script for a number of reasons. Is there some way I can make my function "visible" to sudo without extracting it, finding the appropriate directory, and then executing it as a stand-alone script? The function is about a page long itself and contains multiple strings, some double-quoted and some single-quoted. It is also dependent upon a menu function defined elsewhere in the main script. I would only expect someone with sudo ANY to be able to run the function, as one of the things it does is change passwords.
BryKKan (2267 rep)
Mar 11, 2016, 04:54 AM • Last activity: Jul 2, 2025, 01:28 PM
8 votes
6 answers
15038 views
How to catch and handle nonzero exit status within a Bash function?
Say I have the following (pointless) Bash function: myfunc() { ls failfailfail uptime } I run it as follows: myfunc || echo "Something is wrong." What I want to happen is `ls` runs (as it should), `failfailfail` does not work (since it doesn't exist), and `uptime` doesn't run. The return value of th...
Say I have the following (pointless) Bash function: myfunc() { ls failfailfail uptime } I run it as follows: myfunc || echo "Something is wrong." What I want to happen is ls runs (as it should), failfailfail does not work (since it doesn't exist), and uptime doesn't run. The return value of the function would be nonzero, and the error message would be shown. The return value doesn't have to be the exact exit status of the failed command, it just shouldn't be zero. What actually happens is I get the output of ls, followed by "-bash: failfailfail: command not found", followed by the output of uptime. The error message is not shown, because the failed exit status is getting eaten. set -e has no useful effect, either within the function or in the scope where the function is called. The only way I can get this to work the way I want is: myfunc() { ls || return $? failfailfail || return $? uptime || return $? } But this seems awfully repetitive and ugly. Is there another way to clean this up?
smitelli (308 rep)
Apr 28, 2016, 04:15 PM • Last activity: Jun 23, 2025, 08:08 PM
66 votes
5 answers
77077 views
What is "declare" in Bash?
After reading ilkkachu's answer to [this question][1] I learned on the existence of the `declare` (with argument `-n`) shell built in. `help declare` brings: > Set variable values and attributes. > > Declare variables and give them attributes. If no NAMEs are given, > display the attributes and valu...
After reading ilkkachu's answer to this question I learned on the existence of the declare (with argument -n) shell built in. help declare brings: > Set variable values and attributes. > > Declare variables and give them attributes. If no NAMEs are given, > display the attributes and values of all variables. > -n ... make NAME a reference to the variable named by its value I ask for a general explanation with an example regarding declare because I don't understand the man. I know what is a variable and expanding it but I still miss the man on declare (variable attribute?). Maybe you'd like to explain this based on the code by ilkkachu in the answer: #!/bin/bash function read_and_verify { read -p "Please enter value for '$1': " tmp1 read -p "Please repeat the value to verify: " tmp2 if [ "$tmp1" != "$tmp2" ]; then echo "Values unmatched. Please try again."; return 2 else declare -n ref="$1" ref=$tmp1 fi }
user149572
Apr 3, 2019, 06:49 AM • Last activity: Jun 11, 2025, 10:39 AM
0 votes
1 answers
32 views
How to keep a local function private in a zsh `autoload` module?
I want to define a helper function in a zsh `autoload`-ed module. The problem is, if I just define in my `my_autoloaded_fn` file such as ```zsh function helper { # ... } helper a helper b ``` the name `helper` will become defined in the global namespace once `my_autoloaded_fn` is invoked. I tried al...
I want to define a helper function in a zsh autoload-ed module. The problem is, if I just define in my my_autoloaded_fn file such as
function helper {
  # ...
}

helper a
helper b
the name helper will become defined in the global namespace once my_autoloaded_fn is invoked. I tried also
local helper
function helper {
  # ...
}
but the local declaration seems to have no effect. And neither local -f works.
Petr (1776 rep)
May 19, 2025, 01:28 PM
2 votes
4 answers
165 views
Is there a Bash variable containing the name of the previously executed function?
I want to line up a couple of Bash functions based on the success or failure of the execution of the preceding function. If something fails, I want to print an error message: `function_x has failed`. **Example 1** ```bash function_x() { false } if ! function_x ; then echo "function_x has failed" els...
I want to line up a couple of Bash functions based on the success or failure of the execution of the preceding function. If something fails, I want to print an error message: function_x has failed. **Example 1**
function_x() {
  false
}

if ! function_x ; then
  echo "function_x has failed"
else
  echo "call another function here"
fi
So the above works fine, but I would like to make the content of the error message more specific than above, maybe through the use of an environment variable carrying the name of the previously run function. Something like below: **Example 2**
if ! function_x ; then
  echo "${PREVIOUS_FUNCTION} has failed"
else
  echo "call another function here"
fi
Now, my question is whether such a generic environment variable exists, or whether there is some other way to make that error message "function [function_name] has failed" more generic than in Example 1.
vrms (287 rep)
May 4, 2025, 04:33 AM • Last activity: May 5, 2025, 10:57 AM
0 votes
0 answers
26 views
Why is set -e also ignored for functions called via command substitution
I've seen [questions][1] [about][2] this topic, but they talk about constructs like `if` or `||`. I don't understand why the same behavior seem to happen for substitution (`$()`)? ``` $ my_function() { echo "the following command could fail:"; false; echo "this is after the command that fails"; } $...
I've seen questions about this topic, but they talk about constructs like if or ||. I don't understand why the same behavior seem to happen for substitution ($())?
$ my_function() {     echo "the following command could fail:";     false;     echo "this is after the command that fails"; }
$ (set -ex; var=$(my_function); echo "$var" )
++ my_function
++ echo 'the following command could fail:'
++ false
++ echo 'this is after the command that fails'
+ var='the following command could fail:
this is after the command that fails'
+ echo 'the following command could fail:
this is after the command that fails'
the following command could fail:
this is after the command that fails
vs
$ my_function() { set -e;     echo "the following command could fail:";     false;     echo "this is after the command that fails"; }
$ (set -ex; var=$(my_function); echo "$var" )
++ my_function
++ set -e
++ echo 'the following command could fail:'
++ false
+ var='the following command could fail:'
errexit seems to behave as expected for simple commands:
$ (set -ex; var=$(false); echo "$var" )
++ false
+ var=
If I use read instead I get the expected behaviour:
$ my_function() {     echo "the following command could fail:";     false;     echo "this is after the command that fails"; }
$ (set -exo pipefail; my_function | read var; echo "$var" )
+ my_function
+ echo 'the following command could fail:'
+ read var
+ false
Jakub Bochenski (325 rep)
Apr 29, 2025, 03:30 PM • Last activity: Apr 29, 2025, 03:36 PM
4 votes
1 answers
218 views
Run in background avoiding any job control message from the shell
Lets define a shell function (here the shell is Bash) and test it $ s () { xterm -e sleep 5 & } $ s [1] 307926 $ [1]+ Done xterm -e sleep 5 $ With my specific meaning of *better*, I can redefine `s` like this $ s () { xterm -e sleep 5 & disown ; } $ s [1] 307932 $ $ (no message from the shell when t...
Lets define a shell function (here the shell is Bash) and test it $ s () { xterm -e sleep 5 & } $ s 307926 $ + Done xterm -e sleep 5 $ With my specific meaning of *better*, I can redefine s like this $ s () { xterm -e sleep 5 & disown ; } $ s 307932 $ $ (no message from the shell when the job is finished). Here I have to ask, is it possible to define s so that I have $ s () { pre_magic xterm -e sleep 5 post_magic ; } $ s $ $ i.e., suppress the job info printed on terminal by the shell?
gboffi (1376 rep)
Apr 17, 2025, 01:52 PM • Last activity: Apr 17, 2025, 02:21 PM
4 votes
3 answers
3615 views
How to prefix every argument with '-p' in Bash?
How do I prefix `-p` to every argument passed to my function? Modifying the arguments themselves and creating a new array are both fine.
How do I prefix -p to every argument passed to my function? Modifying the arguments themselves and creating a new array are both fine.
user541686 (3163 rep)
Jul 14, 2011, 03:34 AM • Last activity: Feb 22, 2025, 01:16 PM
88 votes
14 answers
51794 views
Why write an entire bash script in functions?
At work, I write bash scripts frequently. My supervisor has suggested that the entire script be broken into functions, similar to the following example: #!/bin/bash # Configure variables declare_variables() { noun=geese count=three } # Announce something i_am_foo() { echo "I am foo" sleep 0.5 echo "...
At work, I write bash scripts frequently. My supervisor has suggested that the entire script be broken into functions, similar to the following example: #!/bin/bash # Configure variables declare_variables() { noun=geese count=three } # Announce something i_am_foo() { echo "I am foo" sleep 0.5 echo "hear me roar!" } # Tell a joke walk_into_bar() { echo "So these ${count} ${noun} walk into a bar..." } # Emulate a pendulum clock for a bit do_baz() { for i in {1..6}; do expr $i % 2 >/dev/null && echo "tick" || echo "tock" sleep 1 done } # Establish run order main() { declare_variables i_am_foo walk_into_bar do_baz } main Is there any reason to do this other than "readability", which I think could be equally well established with a few more comments and some line spacing? Does it make the script run more efficiently (I would actually expect the opposite, if anything), or does it make it easier to modify the code beyond the aforementioned readability potential? Or is it really just a stylistic preference? Please note that although the script doesn't demonstrate it well, the "run order" of the functions in our actual scripts tends to be very linear -- walk_into_bar depends on stuff that i_am_foo has done, and do_baz acts on stuff set up by walk_into_bar -- so being able to arbitrarily swap the run order isn't something we would generally be doing. For example, you wouldn't suddenly want to put declare_variables after walk_into_bar, that would break things. An example of how I would write the above script would be: #!/bin/bash # Configure variables noun=geese count=three # Announce something echo "I am foo" sleep 0.5 echo "hear me roar!" # Tell a joke echo "So these ${count} ${noun} walk into a bar..." # Emulate a pendulum clock for a bit for i in {1..6}; do expr $i % 2 >/dev/null && echo "tick" || echo "tock" sleep 1 done
Doktor J (2672 rep)
Sep 29, 2016, 06:45 PM • Last activity: Jan 28, 2025, 10:11 PM
31 votes
9 answers
25704 views
How to set an alias on a per-directory basis?
Suppose you have an alias `go`, but want it to do different things in different directories? In one directory it should run `cmd1`, but in another directory it should run `cmd2` By the way, I have an aliases for switching to the above directories already, so is it possible to append the `go` alias a...
Suppose you have an alias go, but want it to do different things in different directories? In one directory it should run cmd1, but in another directory it should run cmd2 By the way, I have an aliases for switching to the above directories already, so is it possible to append the go alias assignment to the foo alias? alias "foo=cd /path/to/foo" Working in bash(?) on OSX.
B Seven (8469 rep)
Oct 26, 2012, 06:54 PM • Last activity: Jan 16, 2025, 11:43 AM
2 votes
2 answers
2630 views
Passing options/args/parameters with spaces from the script to a function within
I've got a script that I am passing arguments/options/parameters to at the command line. One of the values has a space in it, which I have put in double quotes. It might be easier to provide an example. Forgive my usage of arguments/options/parameters. $: ./test1.ksh -n -b -d "Home Videos" My proble...
I've got a script that I am passing arguments/options/parameters to at the command line. One of the values has a space in it, which I have put in double quotes. It might be easier to provide an example. Forgive my usage of arguments/options/parameters. $: ./test1.ksh -n -b -d "Home Videos" My problem is setting a variable to "Home Videos" and it being used together. In my example, the -d is to specify a directory. Not all the directories have spaces, but some do in my case. This is an example of the code I have that is not working as expected: #!/bin/ksh Function1() { echo "Number of Args in Function1: $#" echo "Function1 Args: $@" SetArgs $* } SetArgs() { echo -e "\nNumber of Args in SetArgs: $#" echo "SetArgs Args: $@" while [ $# -gt 0 ] do case $1 in -[dD]) shift export DirectoryName=$1 ;; -[nN]) export Var1=No shift ;; -[bB]) export Var2=Backup shift ;; *) shift ;; esac done Function2 } Function2() { echo "Directory Name: ${DirectoryName}" } Function1 $* When I run this, I'm getting only Home for the DirectoryName instead of Home Videos. Seen below. $ ./test1.ksh -n -b -d "Home Videos" Number of Args in Function1: 5 Function1 Args: -n -b -d Home Videos Number of Args in SetArgs: 5 SetArgs Args: -n -b -d Home Videos Var1 is set to: No Var2 is set to: Backup Directory Name: Home What I am expecting and I have not been able to get it to happen is: $ ./test1.ksh -n -b -d "Home Videos" Number of Args in Function1: 4 Function1 Args: -n -b -d "Home Videos" Number of Args in SetArgs: 4 SetArgs Args: -n -b -d "Home Videos" Var1 is set to: No Var2 is set to: Backup Directory Name: Home Videos <-- Without double quotes in the final usage. I've tried escaping the double quotes, without any success.
DNadler (23 rep)
Nov 21, 2017, 11:05 AM • Last activity: Dec 31, 2024, 10:23 AM
7 votes
1 answers
579 views
bash - how to remove a local variable (inside a function)
I've read what's listed in Bibliography regarding `unset`, `declare`, `local` and "Shell Functions". My version of Bash is ``` GNU bash, version 5.1.16(1)-release (x86_64-pc-linux-gnu) ``` ``` var='outer' declare -p var unset var declare -p var function foo { echo \""I'm in"\" local var='inner' decl...
I've read what's listed in Bibliography regarding unset, declare, local and "Shell Functions". My version of Bash is
GNU bash, version 5.1.16(1)-release (x86_64-pc-linux-gnu)
var='outer'
declare -p var
unset var
declare -p var
function foo {
  echo \""I'm in"\"
  local var='inner'
  declare -p var
  unset var
  declare -p var
}
foo
(the strange quoting around I'm in is there just to preserve syntax highlithing in the following block quote.) This prints
declare -- var="outer"
bash: declare: var: not found
"I'm in"
declare -- var="inner"
declare -- var
There is a difference in unsetting a global variable and unsetting a local variable inside a function. In the former case, the variable is removed. In the latter, the variable stays declared (but unset). Is there a way to completely remove a local variable inside a function (before the function returns)? That is that the output would be
declare -- var="outer"
bash: declare: var: not found
"I'm in"
declare -- var="inner"
bash: declare: var: not found
That would be useful to test if a variable is non existing inside a function, like in
function foo {
  local var
  while
    declare -p var
  do
    echo "$var"
    ((var++))
    [[ "$var" -eq 4 ]] \
    && unset var
  done
}
This code loops indefinitely, printing
declare -- var="1"
1
declare -- var="2"
2
declare -- var="3"
3
declare -- var

declare -- var="1"
1
declare -- var="2"
2
declare -- var="3"
3
declare -- var
[omissis]
Is there anything wrong in checking if a variable exists using declare -p? The only mention I found in the Bash reference manual about the difference between unsetting a global variable and a local one is > If a variable at the current local scope is unset, it will remain so (appearing as unset) until it is reset in that scope or until the function returns. (ref. Bash reference manual - sec. "Shell Functions") where the word _appearing_ is the only clue. **Bibliography** + [Bash reference manual] sec. "4 Shell Builtin Commands" + [What does unset do?]
the_eraser (185 rep)
Dec 10, 2024, 02:09 PM • Last activity: Dec 10, 2024, 05:34 PM
55 votes
4 answers
26335 views
what is the zsh equivalent of bash's export -f
So I started using `zsh`. I like it all right. It seems very cool and slick, and the fact that the current working directory and actual command line are on different lines is nice, but at the same time, I'm noticing that `zsh` can be a bit slower than `bash`, especially when printing text to the scr...
So I started using zsh. I like it all right. It seems very cool and slick, and the fact that the current working directory and actual command line are on different lines is nice, but at the same time, I'm noticing that zsh can be a bit slower than bash, especially when printing text to the screen. The thing I liked best was the fact that zsh was 'backward compatible' with all of the functions I defined in my .bashrc. One gripe though. The functions all work perfectly, but I can't figure out how the exporting system works. I had some of those .bashrc functions exported so that I could use them elsewhere, such as in scripts and external programs, with export -f. In zsh, exporting doesn't seem to even be talked about. Is it autoloading? Are those two things the same? I'm having a seriously hard time figuring that out.
ixtmixilix (13520 rep)
Dec 25, 2012, 12:54 AM • Last activity: Oct 21, 2024, 08:18 PM
2 votes
1 answers
196 views
Why does a 'pipe-to-awk' behave differently inside a function?
I'm using `alsa` to fiddle around with the volume on a Bluetooth speaker I have connected. It's a 1-speaker setup; just something to provide some background. I can 'get' the volume setting fm the CLI as follows: ```bash $ amixer sget Master Simple mixer control 'Master',0 Capabilities: pvolume pswit...
I'm using alsa to fiddle around with the volume on a Bluetooth speaker I have connected. It's a 1-speaker setup; just something to provide some background. I can 'get' the volume setting fm the CLI as follows:
$ amixer sget Master
Simple mixer control 'Master',0
  Capabilities: pvolume pswitch pswitch-joined
  Playback channels: Front Left - Front Right
  Limits: Playback 0 - 65536
  Mono:
  Front Left: Playback 22938 [35%] [on]
  Front Right: Playback 22938 [35%] [on]
I can 'set' the volume fm the CLI as follows:
$ amixer sset Master 50%
Simple mixer control 'Master',0
  Capabilities: pvolume pswitch pswitch-joined
  Playback channels: Front Left - Front Right
  Limits: Playback 0 - 65536
  Mono:
  Front Left: Playback 32768 [50%] [on]
  Front Right: Playback 32768 [50%] [on]
I don't need all this *verbosity*, so I decided to create a function, and two aliases in my ~/.bashrc file to reduce that. The function is not working as I expected: From the CLI, this works fine:
$ amixer sget Master | awk -F"[][]" '/Right:/ { print $2 }'
35%
But when I put this into my function statement in ~/.bashrc, it works ***differently***:
# functions & aliases for alsa mixer/volume control
function vol-get() {
   amixer sget Master | awk -F"[][]" '/Left:/ { print $2 }'
}
export -f vol-get

alias vol-up='amixer sset Master 5%+ > /dev/null && vol-get'
alias vol-dn='amixer sset Master 5%- > /dev/null && vol-get'
Re-reading ~/.bashrc & running the vol-get function yields the following:
$ . ~/.bashrc
$ vol-get
  Front Left: Playback 22938 [35%] [on]
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ?? what happened here ??
$ vol-up
  Front Left: Playback 26215 [40%] [on]
$
So - I'm *close*, but I don't understand why my | awk ... behaves differently inside the function than it does on the command line. Can someone explain and correct this? --- ### Edits for answers to some of the Questions raised in the comments: #### EDIT #1:
$ command -V vol-get
vol-get is a function
vol-get ()
{
    amixer sget Master | awk -F"[][]" '/Left:/ { print $2 }'
} 

$ awk --version
awk: not an option: --version
$ man awk
# reveals that I am actually calling mawk, Version 1.3.4
#### EDIT #2: RE: non-printing characters; note this is a partial c&p from the output (i.e. verbatim):
$ cat -vet ~/.bashrc
   ...
   function vol-get() {$
       amixer sget Master | awk -F'[][]' '/Left:/ { print $2 }'$
   }$
   ...
Seamus (3772 rep)
Oct 19, 2024, 07:21 AM • Last activity: Oct 20, 2024, 09:46 PM
73 votes
6 answers
91433 views
Scope of Local Variables in Shell Functions
After reading [24.2. Local Variables](http://tldp.org/LDP/abs/html/localvar.html), I thought that declaring a variable `var` with the keyword `local` meant that `var`'s value was only accessible within the block of code delimited by the curly braces of a function. However, after running the followin...
After reading [24.2. Local Variables](http://tldp.org/LDP/abs/html/localvar.html) , I thought that declaring a variable var with the keyword local meant that var's value was only accessible within the block of code delimited by the curly braces of a function. However, after running the following example, I found out that var can also be accessed, read and written from the functions invoked by that block of code -- i.e. even though var is declared local to outerFunc, innerFunc is still able to read it and alter its value. [**Run It Online**](http://www.tutorialspoint.com/execute_bash_online.php?PID=0Bw_CjBb95KQMd1ptTmpoOWUyS3M) #!/usr/bin/env bash function innerFunc() { var='new value' echo "innerFunc: [var:${var}]" } function outerFunc() { local var='initial value' echo "outerFunc: before innerFunc: [var:${var}]" innerFunc echo "outerFunc: after innerFunc: [var:${var}]" } echo "global: before outerFunc: [var:${var}]" outerFunc echo "global: after outerFunc: [var:${var}]" Output: global: before outerFunc: [var:] # as expected, var is not accessible outside of outerFunc outerFunc: before innerFunc: [var:initial value] innerFunc: [var:new value] # innerFunc has access to var ?? outerFunc: after innerFunc: [var:new value] # the modification of var by innerFunc is visible to outerFunc ?? global: after outerFunc: [var:] **Q: Is that a bug in my shell (bash 4.3.42, Ubuntu 16.04, 64bit) or is it the expected behavior ?** **EDIT:** Solved. As noted by @MarkPlotnick, this is indeed the expected behavior.
maddouri (831 rep)
May 11, 2016, 04:22 PM • Last activity: Oct 18, 2024, 07:07 PM
24 votes
3 answers
56364 views
Bash Scripting echo locally in a function
In bash scripts I try to keep my variables local to functions wherever I can and then pass what I need out of functions like bellow #!/bin/bash function FUNCTION() { local LOCAL="value" echo "$LOCAL" # return this variable } GLOBAL=$(FUNCTION) echo "$GLOBAL" But is it possible to do this while inclu...
In bash scripts I try to keep my variables local to functions wherever I can and then pass what I need out of functions like bellow #!/bin/bash function FUNCTION() { local LOCAL="value" echo "$LOCAL" # return this variable } GLOBAL=$(FUNCTION) echo "$GLOBAL" But is it possible to do this while including the function's own echos so that if the function has it's own messages to output I don't have to catch them in a variable #!/bin/bash function FUNCTION() { local LOCAL="value" echo "$LOCAL" # return this variable echo "This function is done now" # do not return this variable } GLOBAL=$(FUNCTION) echo "$GLOBAL" # should only echo 'value'
TheLovelySausage (4443 rep)
Oct 15, 2015, 11:07 AM • Last activity: Oct 17, 2024, 08:38 AM
3 votes
1 answers
564 views
Strange variable scope behavior when calling function recursivly
EDIT: sorry. this is my first question here. Here is a minimal working example ``` #!/bin/bash # count=0 function something() { if test -f "$1"; then # is a file ((count++)) echo $count $1 elif test -d "$1"; then # is a folder find $1 | while read line; do if [ $1 != $line ]; then # first line in fi...
EDIT: sorry. this is my first question here. Here is a minimal working example
#!/bin/bash
#
count=0

function something() {
	if test -f "$1"; then
		# is a file
		((count++))
		echo $count $1
	elif test -d "$1"; then
		# is a folder
		find $1 | while read line; do
			if [ $1 != $line ]; then  # first line in find is the folder itself. prevent infinte recursion
				something $line
			fi
		done
	fi
}

while [ $# -gt 0 ]
do
	something "$1"
	shift
done

echo "Processed $count files"
Example output:
$ ./test.sh *
1 0/file1.txt
2 0/file2.txt
1 1/file1.txt
2 1/file2.txt
1 2/file1.txt
2 2/file2.txt
1 3/file1.txt
2 3/file2.txt
1 4/file1.txt
2 4/file2.txt
1 5/file1.txt
2 5/file2.txt
1 6/file1.txt
2 6/file2.txt
1 7/file1.txt
2 7/file2.txt
1 8/file1.txt
2 8/file2.txt
1 9/file1.txt
2 9/file2.txt
1 test.sh
Processed 1 files
As you can see each time I call the function recursively it returns to the variable state on parent function and messes up the count. Using Ubuntu 22.06 on WSL2 VM
Shlomo V (43 rep)
Sep 3, 2024, 07:39 PM • Last activity: Sep 4, 2024, 01:24 PM
Showing page 1 of 20 total questions