Unix & Linux Stack Exchange
Q&A for users of Linux, FreeBSD and other Unix-like operating systems
Latest Questions
3
votes
2
answers
107
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
(126543 rep)
Jul 30, 2025, 04:18 PM
• Last activity: Aug 1, 2025, 01:09 PM
2
votes
2
answers
3506
views
startProcess: posix_spawnp: does not exist (No such file or directory)
I have an interesting case where I'm getting the below error when running a bash program but only when it's run via a systemd unit (running within Nixos). `telegram: startProcess: posix_spawnp: does not exist (No such file or directory)` If I run this program from the command line locally it works w...
I have an interesting case where I'm getting the below error when running a bash program but only when it's run via a systemd unit (running within Nixos).
telegram: startProcess: posix_spawnp: does not exist (No such file or directory)
If I run this program from the command line locally it works with no issue... What might be the cause of this error? It seems like posix_spawnp is actually a syscall which confuses me (why does the error seem to indicate it's an executable?)
The actual script is located here: https://github.com/fabianonline/telegram.sh/blob/master/telegram
Chris Stryczynski
(6593 rep)
Sep 25, 2022, 01:17 PM
• Last activity: Jul 29, 2025, 11:02 PM
2
votes
1
answers
631
views
1-liner process substitution for ksh
I have this command, which works fine for `bash`: `sh <(curl -sSl https://appi.sh/launch)` (launches [this interactive script](https://github.com/Appish/appi.sh/blob/master/launch.sh)) I'd like to get this 1-liner working for `ksh`, too. Currently, it errors with: ``` syntax error: `(' unexpected` `...
I have this command, which works fine for
bash
:
sh <(curl -sSl https://appi.sh/launch)
(launches [this interactive script](https://github.com/Appish/appi.sh/blob/master/launch.sh))
I'd like to get this 1-liner working for ksh
, too. Currently, it errors with:
syntax error: (' unexpected
Running the script from ksh
as sh launch.sh
works fine, so I'm hoping there's a way to have a singular 1-liner that will work in both bash/ksh without exponentially increasing the length of the command.
ljs.dev
(2147 rep)
Jun 17, 2020, 05:58 PM
• Last activity: Jul 22, 2025, 05:09 PM
6
votes
8
answers
14700
views
Check if shell variable contains an absolute path
I want to check if a shell variable contains an absolute path. I don't care if the path exists or not—if it doesn't I'm going to create it—but I do want to ensure that I'm dealing with an absolute pathname. My code looks something like the following: myfunction() { [ magic test to see if "$1" is an...
I want to check if a shell variable contains an absolute path.
I don't care if the path exists or not—if it doesn't I'm going to create it—but I do want to ensure that I'm dealing with an absolute pathname.
My code looks something like the following:
myfunction() {
[ magic test to see if "$1" is an absolute path ] || return 1
mkdir -p "$(dirname "$1")" || return 1
commands >> "$1"
}
Or, the use case where the absolute path to be verified is intended to be a directory:
anotherfunction() {
[ same magic test ] || return 1
mkdir -p "$1"
dostuff >> "$1/somefile"
}
If this were
awk
I would do the check like so: myvar ~ /^\//
There *must* be a clean way to do this with the shell's string handling, but I'm having trouble coming up with it.
(Mentioning a bash
-specific solution would be fine but I'd like to know how to do this portably, also. POSIX string handling seems like it should be sufficient for this.)
Wildcard
(37446 rep)
Jan 20, 2016, 12:57 AM
• Last activity: Jul 20, 2025, 07:52 AM
4
votes
1
answers
323
views
POSIX-compliance of NMAKE
[NMAKE by Microsoft][1] comes with some components of Visual Studio. Is it POSIX-compliant? [1]: https://learn.microsoft.com/en-us/cpp/build/reference/nmake-reference
NMAKE by Microsoft comes with some components of Visual Studio. Is it POSIX-compliant?
Rāṣidu'l-Qamar
(43 rep)
Jul 19, 2025, 05:05 PM
• Last activity: Jul 19, 2025, 06:44 PM
-1
votes
1
answers
1200
views
Specific challenges faced while migrating shell scripts from Solaris 10 to RHEL 7.5
# Source environment: $ uname -a SunOS machine1 5.10 Generic_150400-63 sun4u sparc SUNW,SPARC-Enterprise $ pwd / $ ls -l /bin/sh lrwxrwxrwx 1 root root 13 Nov 1 19:39 /bin/sh -> ../../sbin/sh # Target environment: $ pwd /root $ ls -l /bin/sh lrwxrwxrwx. 1 root root 4 Jul 16 12:10 /bin/sh -> bash $ c...
# Source environment:
$ uname -a
SunOS machine1 5.10 Generic_150400-63 sun4u sparc SUNW,SPARC-Enterprise
$ pwd
/
$ ls -l /bin/sh
lrwxrwxrwx 1 root root 13 Nov 1 19:39 /bin/sh -> ../../sbin/sh
# Target environment:
$ pwd
/root
$ ls -l /bin/sh
lrwxrwxrwx. 1 root root 4 Jul 16 12:10 /bin/sh -> bash
$ cat /etc/system-release
Red Hat Enterprise Linux Server release 7.5 (Maipo)
In target environment, we use shebang line
#!/bin/sh
in every script
----------------------------------------------------
Shell scripts in solaris environment are using shebang line #!/usr/bin/ksh
and #!/bin/sh
Goal is to migrate shell scripts from Solaris 10 to RHEL 7.5
-----------------------------------------------------
1) Are scripts written solaris korn shell & /bin/sh
shell, [posix compliant](http://pubs.opengroup.org/onlinepubs/9699919799/nfindex.html) ? for seamless migration to bash(in Linux) without verification of code..
2) If no, What are the verifications required before migrating scripts to Linux?
overexchange
(1596 rep)
Nov 14, 2018, 03:03 AM
• Last activity: Jul 17, 2025, 12:36 AM
9
votes
2
answers
2508
views
Is Linux considered XSI compliant or largely so?
From APUE > The Single UNIX Specification, a superset of the POSIX.1 standard, > specifies additional interfaces that extend the functionality provided > by the POSIX.1 specification. POSIX.1 is equivalent to the Base > Specifications portion of the Single UNIX Specification. > > The X/Open System Interf...
From APUE
> The Single UNIX Specification, a superset of the POSIX.1 standard,
> specifies additional interfaces that extend the functionality provided
> by the POSIX.1 specification. POSIX.1 is equivalent to the Base
> Specifications portion of the Single UNIX Specification.
>
> The X/Open System Interfaces (XSI) option in POSIX.1 describes
> optional interfaces and defines which optional portions of
> POSIX.1 must be supported for an implementation to be deemed
> XSI conforming. These include file synchronization, thread stack
> address and size attributes, thread process-shared synchronization,
> and the
> _XOPEN_UNIX symbolic constant (marked ‘‘SUS mandatory’’ in Figure 2.5). Only XSI-conforming implementations can be called UNIX systems.
Is it correct that SUS consists exactly of POSIX and XSI?
Is it correct that Linux (or Ubuntu, Debian in particular) is POSIX compliant?
Is Linux (or Ubuntu, Debian in particular) considered XSI compliant or largely so?
I ask this because then I will know whether the parts in APUE labelled for XSI apply to Linux (or Ubuntu, Debian in particular).
I am mainly interested in API, so does that mean Linux kernel suffices?
Tim
(106422 rep)
Sep 5, 2018, 12:43 PM
• Last activity: Jun 20, 2025, 07:38 PM
0
votes
2
answers
62
views
Do race conditions occur during pathname resolution with constant string absolute path literals?
According to *The Open Group Base Specifications Issue 8*, on the rationale of the ```open()``` and ```openat()``` functions: > The purpose of the openat() function is to enable opening files in directories other than the current working directory without exposure to race conditions. Any part of the...
According to *The Open Group Base Specifications Issue 8*, on the rationale of the
()
and ()
functions:
> The purpose of the openat() function is to enable opening files in directories other than the current working directory without exposure to race conditions. Any part of the path of a file could be changed in parallel to a call to open(), resulting in unspecified behavior. By opening a file descriptor for the target directory and using the openat() function it can be guaranteed that the opened file is located relative to the desired directory.
This wording implies that **any use of ()
with a pathname that doesn't refer to a file in the current working directory is potentially subject to race conditions, even if the path is an absolute constant like /dev/null
.** While the string literal is immutable, the underlying path components (/
,
,
) can be altered by another process between resolution steps, leading to unintended behavior or security issues.
For example:
#define _POSIX_C_SOURCE 202405L
#include
#include
int main(void) {
int fd = open("/dev/null", O_RDONLY);
if (fd == -1) {
return 1;
}
...
(void) close(fd);
return 0;
}
So the only safe way to open it would be:
#define _POSIX_C_SOURCE 202405L
#include
#include
int main(void) {
int rootfd = open("/", O_SEARCH);
if (rootfd == -1) {
return 1;
}
int devfd = openat(rootfd, "dev", O_SEARCH | O_DIRECTORY);
if (devfd == -1) {
(void) close(rootfd);
return 1;
}
int nullfd = openat(devfd, "null", O_RDONLY);
if (nullfd == -1) {
(void) close(devfd);
(void) close(rootfd);
return 1;
}
...
(void) close(nullfd);
(void) close(devfd);
(void) close(rootfd);
return 0;
}
But the path used is a constant character literal that wasn't obtained from another function. I understand how a race condition could occur if there were a time window between retrieving the path and actually opening it, but not in this case. Doesn't my ()
example just replicate what the kernel already does internally during path resolution when using ()
with an absolute path?
**Note:** I used /dev/null
because it's guaranteed to exist, but my question applies to any path that refers to any file or directory in the filesystem.
Salubia
(1 rep)
May 19, 2025, 07:21 PM
• Last activity: May 20, 2025, 08:08 AM
0
votes
1
answers
479
views
How to replicate the posix acl default on zfs/nfsv4 acl on Solaris?
Suppose I want a dir, which all files and directories created inside has the group permission of the group owner of the dir, and 770 as default permission. With posix ACL is really easy #create a dir.. mkdir proof #inherit group permission "video" in this example chmod g+s proof/ chgrp video proof/...
Suppose I want a dir, which all files and directories created inside
has the group permission of the group owner of the dir, and 770 as
default permission.
With posix ACL is really easy
#create a dir..
mkdir proof
#inherit group permission "video" in this example
chmod g+s proof/
chgrp video proof/
#with setfacl make the default group with rxw permissions
setfacl -d -m g:video:rwx proof
#other are not allowed
setfacl -d -m o:--- proof/
chmod o-x proof
#give the acl
setfacl -m g:video:rwx proof
Now I create a file and a dir inside the dir proof..
mkdir try1
drwxrws---+ 2 myuser video 4,0K feb 23 01:26 try1
touch file1
-rw-rw----+ 1 myuser video 0 feb 23 01:29 file1
As you can see I obtain what I want, all files in the dir
inherit permissions and has the group "video" as group owner.
This is possible on Linux (posix acl on ext4, btrfs, etc..)
and Solaris (ufs).
Now the question..how to do this with zfs which use nfsv4 acl
on Solaris?
I have tried this making another dir "proof" in a zfs Solaris 11 host
(of course chmod g+s was made)
chmod A=owner@:read_attributes/read_data/execute/list_directory/read_data/write_data/append_data/execute/add_file/add_subdirectory:fd:allow,group:video:read_attributes/read_data/execute/list_directory/read_data/write_data/append_data/execute/add_file/add_subdirectory:fd:allow,everyone@:read_attributes/read_data/execute/list_directory/read_data/write_data/append_data/execute/add_file/add_subdirectory:fd:deny proof
but the result is..
mkdir newdir
drwxr-sr-x+ 2 myuser video 2 23 feb 02.33 newdir
:|
How to obtain the same of posix acl? Thanks
elbarna
(13690 rep)
Feb 23, 2023, 12:35 AM
• Last activity: May 20, 2025, 08:06 AM
15
votes
3
answers
2798
views
Why Linux read() avoids using full 2 GiB in one call
Reading the manual page (`man 2 read`) on my Debian system, I see the following note: >NOTES >[...] >On Linux, `read()` (and similar system calls) will transfer at most > 0x7ffff000 (2,147,479,552) bytes, returning the number of bytes actually > transferred. (This is true on both 32-bit and 64-bit s...
Reading the manual page (
man 2 read
) on my Debian system, I see the following note:
>NOTES
>[...]
>On Linux, read()
(and similar system calls) will transfer at most
> 0x7ffff000 (2,147,479,552) bytes, returning the number of bytes actually
> transferred. (This is true on both 32-bit and 64-bit systems.)
I am guessing something is being done with the remaining 0xfff (4095) bytes so that this number is chosen for a specific implementation detail.
So my question is: Why is it 0x7ffff000 and not simply (naively) 0x7fffffff?
malat
(3429 rep)
Apr 29, 2025, 08:11 AM
• Last activity: May 6, 2025, 05:20 AM
12
votes
1
answers
908
views
How are specification issues / defects of POSIX collected and how can I participate?
While [pondering whether IEEE 1003.1-2017 forbids race-condition safe `ln -f`](https://unix.stackexchange.com/questions/794236/idiomatic-way-of-generating-a-unique-filename/794239#comment1526091_794239), it occurred to me: Even if this is really an unfortunate definition (which GNU coreutils' `ln` t...
While [pondering whether IEEE 1003.1-2017 forbids race-condition safe
ln -f
](https://unix.stackexchange.com/questions/794236/idiomatic-way-of-generating-a-unique-filename/794239#comment1526091_794239) , it occurred to me:
Even if this is really an unfortunate definition (which GNU coreutils' ln
thankfully ignores), I would have no way to say "hey, dear standardizers, next iteration, maybe don't specify this broken thing, and instead demand this safe thing, or at least don't prohibit safe implementation".
How does the evolution of the POSIX / IEEE 1003.1 standard actually happen? How can the interested public participate, if at all?
Marcus Müller
(47087 rep)
May 4, 2025, 01:27 PM
• Last activity: May 4, 2025, 01:42 PM
3
votes
2
answers
3797
views
Recommended scheme for partitioning root file system into subvolumes following the Filesystem Hierarchy Standard
The [Filesystem Hierarchy Standard][1] (FHS) is the formal codification for root file tree on Linux installations, as inherited from earlier iterations of Unix and POSIX, and subsequently adapted. It standardizes the exact uses of the familiar `/home`, `/etc`, `/usr`, `/var`, and so on, from various...
The Filesystem Hierarchy Standard (FHS) is the formal codification for root file tree on Linux installations, as inherited from earlier iterations of Unix and POSIX, and subsequently adapted. It standardizes the exact uses of the familiar
/home
, /etc
, /usr
, /var
, and so on, from various historic differences of convention, and resolves where application-specific and site-specific file names may be added, or not.
Basic Linux installations historically have placed the entire tree on a single file system, though some variations have utilized a separate partition for /home
, presumably to facilitate backup and migration.
More recently, Btrfs has gained increasing adoption, which allows a single partition to host various subvolumes. Subvolumes are appealing because they may be captured in snapshots, and require no pre-allocation of space.
The mapping of subvolumes to nodes on the FSH appears to vary widely.
Sensible standards and policies respecting such matters are important, for supporting optimal management of files on the system with respect to snaphots and related concerns.
Following are some observations:
- Debian appears to place the entire tree on a single subvolume beneath root.
- Ubuntu appears to allocate a subvolume for /home
, and another for the remainder of the root tree.
- Arch Linux appears to extend the separation adopted by Debian by placing /var/log
and /var/cache
each in a separate subvolume.
- openSUSE has a single subvolume for /var
, and one each for /home
, /root
, /usr/local
, /opt
, and /srv
, as well as one for the remainder of the root tree, a further one for each installed grub architecture.
Have any standards emerged that have attempted to resolve the various design considerations, and to unify the approaches adopted by various operating systems? Has any agreement emerged concerning how to reconcile the functions of the various file tree nodes with policies concerning snapshots?
brainchild
(340 rep)
Nov 8, 2022, 02:11 PM
• Last activity: Apr 11, 2025, 05:07 AM
0
votes
2
answers
6207
views
How to get list of Linux capabilities
I need to get a list of capabilities available to the version of linux on which the program is executed. Just in order to give user possibility to choose what capability to grant to the file. Is there any chance to do this using some standard libraries? The only way I managed to do this is to look a...
I need to get a list of capabilities available to the version of linux on which the program is executed. Just in order to give user possibility to choose what capability to grant to the file. Is there any chance to do this using some standard libraries? The only way I managed to do this is to look at the bounding set of
cash --print
, but
1. Somewhy it displayes ...,cap_audit_read,38,39
, while /usr/include/linux/capability.h
says that CAP_LAST_CAP
is CAP_AUDIT_READ(37)
2. I would really use some descriptions to capabilities, if it is possible
Ekaterina
(57 rep)
Mar 28, 2022, 03:52 PM
• Last activity: Mar 22, 2025, 11:51 AM
1
votes
4
answers
140
views
Need shell script help - processing the same option multiple times
So I've ran into a bit of a wall, I have an option in my script that calls a function which allows me to specify a file/directory and then I want to parse that output into a menu tool (using dmenu in this case) to select which file is the one I want specifically and continue working with that select...
So I've ran into a bit of a wall, I have an option in my script that calls a function which allows me to specify a file/directory and then I want to parse that output into a menu tool (using dmenu in this case) to select which file is the one I want specifically and continue working with that selection as a variable
in the same script. This works fine if it's just one file or directory, but I want to be able to use the option multiple times and then parse all of that output at once to dmenu. Here's a snippet
fileSelection () {
if [ -d "${OPTARG}" ]; then find "${OPTARG}" -type f; fi;
if [ -f "${OPTARG}" ]; then printf '%s\n' "${OPTARG}"; fi;
}
while getopts "f:" option; do
case "${option}" in
f) file="$(fileSelection|dmenu)";;
esac
done
And like I said this works if I do:
myscript -f file
or
myscript -f directory
but I was hoping to also be able to do this:
myscript -f file1 -f file2
The problem is, since the function is called consecutively I can't parse the output into dmenu like that, because it doesn't invoke dmenu with options file1 and file2, but first with file1 and then with file2, I hope this makes sense.
There might be some really simple solution I am missing, I've thought about simply writing the output into a file and then parsing that which might work, but I'd like to avoid piping to files if possible. I am also trying to keep it POSIX compliant, and would appreciate answers that follow that.
hollowillow
(11 rep)
Mar 18, 2025, 10:09 PM
• Last activity: Mar 20, 2025, 07:58 PM
4
votes
5
answers
23281
views
Argument list too long error with makefile
In a makefile, I have @echo "$(IGNORE_DIRS) $(CLEAN_FILES) $(CLEAN_DIRS) $(REALCLEAN_FILES)" | tr ' ' '\n' >> $@ The problem is that `$(CLEAN_FILES)` is quite large, so when I run make, I get make: execvp: /bin/sh: Argument list too long I'm on Xubuntu 18.10. Edit: I should provide a little more con...
In a makefile, I have
@echo "$(IGNORE_DIRS) $(CLEAN_FILES) $(CLEAN_DIRS) $(REALCLEAN_FILES)" | tr ' ' '\n' >> $@
The problem is that
$(CLEAN_FILES)
is quite large, so when I run make, I get
make: execvp: /bin/sh: Argument list too long
I'm on Xubuntu 18.10.
Edit: I should provide a little more context. What I am working on is a make rule (I'm using GNU make) to automatically generate the .hgignore
file. Here is the make rule in its entirety:
.hgignore : .hgignore_extra
@echo "Making $@"
@rm -f $@
@echo "# Automatically generated by Make. Edit .hgignore_extra instead." > $@
@tail -n +2 $> $@
@echo "" >> $@
@echo "# The following files come from the Makefile." >> $@
@echo "syntax: glob" >> $@
@echo "$(IGNORE_DIRS) $(CLEAN_FILES) $(CLEAN_DIRS) $(REALCLEAN_FILES)" | tr ' ' '\n' >> $@
@chmod a-w $@
.PHONY : .hgignore
Edit 2: At @mosvy 's suggestion, I have also tried
.hgignore : .hgignore_extra
@echo "Making $@"
@rm -f $@
@echo "# Automatically generated by Make. Edit .hgignore_extra instead." > $@
@tail -n +2 $> $@
@echo "" >> $@
@echo "# The following files come from the Makefile." >> $@
@echo "syntax: glob" >> $@
$(file >$@) $(foreach V,$(IGNORE_DIRS) $(CLEAN_FILES) $(CLEAN_DIRS) $(REALCLEAN_FILES),$(file >>$@,$V))
@true
@chmod a-w $@
.PHONY : .hgignore
Running make .hgignore
with this, I no longer get the "Argument list too long" error, but the generated .hgignore file only contains output up to the syntax: glob
line, and then nothing after that.
teerav42
(159 rep)
Nov 9, 2018, 01:51 AM
• Last activity: Mar 20, 2025, 04:09 PM
2
votes
1
answers
149
views
What is the origin of the -E option of the `realpath` command in POSIX issue 8?
The `realpath` command utility is now defined by POSIX in its issue 8 (2024): realpath — resolve a pathname > **realpath [-E|-e] file** > > The realpath utility shall canonicalize the pathname specified by the file operand as follows: > > If a call to the `realpath()` function with the specified pat...
The
realpath
command utility is now defined by POSIX in its issue 8 (2024): realpath — resolve a pathname
> **realpath [-E|-e] file**
>
> The realpath utility shall canonicalize the pathname specified by the file operand as follows:
>
> If a call to the realpath()
function with the specified pathname as its first argument would succeed, the canonicalized pathname shall be the pathname that would be returned by that realpath()
call. Otherwise:
>
> * If the **-e** option is specified, the canonicalization shall fail.
>
> * If the **-E** option is specified, then if a call to the realpath()
function with the specified pathname as its first argument would encounter an error condition other than [ENOENT], the canonicalization shall fail; if the call would encounter an [ENOENT] error, realpath shall expand all symbolic links that would be encountered in an attempt to resolve the specified pathname using the algorithm specified in XBD 4.16 Pathname Resolution, except that any trailing ` characters that are not also leading
characters shall be ignored. If this expansion succeeds and the path prefix of the expanded pathname resolves to an existing directory, the canonicalized pathname shall be the expanded pathname. In all other cases, the canonicalization shall fail. If the expanded pathname is not empty, does not begin with a
, and has exactly one pathname component, it shall be treated as if it had a path prefix of "
./`".
>
> * If no options are specified, realpath shall canonicalize the specified pathname in an unspecified manner such that the resulting absolute pathname does not contain any components that refer to files of type symbolic link and does not contain any components that are dot or dot-dot.
>
> Upon successful canonicalization, realpath shall write the canonicalized pathname, followed by a `` character, to standard output.
>
> If canonicalization fails, or the canonicalized pathname is empty, nothing shall be written to standard output, a diagnostic message shall be written to standard error, and realpath shall exit with non-zero status.
>
> _[...]_
My question is: the -e
option of realpath
is already supported by at least GNU and Solaris, but I can't find any mention of the -E
option in any realpath
that I could check (macOS, FreeBSD, Solaris, GNU). Did the OpenGroup invent it?
Fravadona
(1581 rep)
Mar 14, 2025, 01:49 PM
• Last activity: Mar 15, 2025, 03:39 AM
7
votes
2
answers
983
views
How to find out if a command wrote to stdout or not
I'd like to figure out if an external program ran successfully and wrote something to stdout, or if it did not write anything, which happens in case an error occurred. The program unfortunately always returns with exit status 0 and no stderr output. The check should also not modify or hide whatever...
I'd like to figure out if an external program ran successfully and wrote something to stdout, or if it did not write anything, which happens in case an error occurred. The program unfortunately always returns with exit status 0 and no stderr output. The check should also not modify or hide whatever is being written to stdout by the program.
---
If program output is short, it's possible to use command substitution to capture it, store it in an environment variable and print it again:
output="$(external_program)"
printf %s "$output"
if [ -z "$output" ]; then
# error: external program didn't write anything
fi
Possible dealbreakers:
- Depends on size of output, see https://unix.stackexchange.com/questions/357843/setting-a-long-environment-variable-breaks-a-lot-of-commands
- Possibly modifies output, notably removes newlines, see https://unix.stackexchange.com/questions/164508/why-do-newline-characters-get-lost-when-using-command-substitution
- If external program output is binary data, it's not a good idea to store that in an environment variable (?)
---
Another possibility would be to write the output to a temporary file or pipe. This could be wrapped into a function which communicates the result via exit status:
output_exist() (
temporary_file="$(mktemp)" || exit
trap 'rm "$temporary_file"' EXIT
tee "$temporary_file"
test -s "$temporary_file"
)
if ! external_program | output_exist; then
# error: external program didn't write anything
fi
Possible dealbreakers:
- Temporary file or pipe that has to be taken care of, ensure clean-up etc., convenience vs. portability, e.g. POSIX only has mktemp(3)
, no mktemp(1)
- Very large output may lead to resource/performance issues
---
What alternatives are there? Is there a more straightforward solution?
finefoot
(3554 rep)
Mar 9, 2025, 05:55 PM
• Last activity: Mar 10, 2025, 09:20 AM
5
votes
2
answers
294
views
Duplicate stdout to pipe into another command with named pipe in POSIX shell script function
``` mkfifo foo printf %s\\n bar | tee foo & tr -s '[:lower:]' '[:upper:]' <foo wait rm foo ``` This is a working POSIX shell script of what I want to do: - `printf %s\\n bar` is symbolic for an external program producing stdout - `tr -s '[:lower:]' '[:upper:]'` is symbolic for another command that i...
mkfifo foo
printf %s\\n bar | tee foo &
tr -s '[:lower:]' '[:upper:]'
This is a working POSIX shell script of what I want to do:
- printf %s\\n bar
is symbolic for an external program producing stdout
- tr -s '[:lower:]' '[:upper:]'
is symbolic for another command that is supposed to receive the stdout and do something with it
- tee
duplicates stdout to named pipe foo
And the output is as expected:
bar
BAR
Now I'd like to tidy up the code so it becomes external_program | my_function
. Something like this:
f() (
mkfifo foo
tee foo &
tr -s '[:lower:]' '[:upper:]'
But now there is no output at all.
finefoot
(3554 rep)
Mar 9, 2025, 01:34 PM
• Last activity: Mar 9, 2025, 03:19 PM
27
votes
2
answers
4084
views
Why is there no mktemp command in POSIX?
One of the most common things shell scripts need to do is to create and manipulate temporary files. Doing so safely is a pain, since you need to avoid name clashes, avoid race conditions, make sure the file has the correct permissions, etc. (See the [GNU Coreutils manual](https://www.gnu.org/softwar...
One of the most common things shell scripts need to do is to create and manipulate temporary files. Doing so safely is a pain, since you need to avoid name clashes, avoid race conditions, make sure the file has the correct permissions, etc. (See the [GNU Coreutils manual](https://www.gnu.org/software/coreutils/manual/html_node/mktemp-invocation.html#mktemp-invocation) and [this Signs of Triviality blog post](https://www.netmeister.org/blog/mktemp.html) for a more detailed discussion of these issues.) Most Unix-like operating systems solve this problem by providing a
mktemp
command that takes care of all these gotchas. However, [the syntax and semantics of these mktemp
commands are not standardized](https://stackoverflow.com/a/2792789/906070) . If you really want to create a temp file both safely _and_ portably, you have to resort to [ugly kludges](https://unix.stackexchange.com/a/181996/37849) such as the following:
tmpfile=$(
echo 'mkstemp(template)' |
m4 -D template="${TMPDIR:-/tmp}/baseXXXXXX"
) || exit
(This workaround exploits the fact that the macro processor m4
is part of POSIX, and m4
exposes the C standard library function mkstemp()
which is also defined by POSIX.)
Given all this, why hasn't POSIX standardized a mktemp
command, guaranteeing its presence and at least certain aspects of its behaviour? Is this a glaring oversight on the part of the POSIX committee, or has the idea of standardizing a mktemp
actually been discussed by the committee and rejected for some technical or other reason?
Psychonaut
(974 rep)
Oct 16, 2020, 09:17 AM
• Last activity: Feb 28, 2025, 09:00 AM
0
votes
1
answers
67
views
Change stdout for shell to pipe
With exec >LOG 2>&1 I can change stdout and stderr for the current shell, so all following commands will inherit those file descriptors. Is there a way to change stdout/stderr for the current shell to a pipe? I've tried exec | gpg -aer 0x6aabe354 in the hope to replace current stdout with gnupg, enc...
With
exec >LOG 2>&1
I can change stdout and stderr for the current shell, so all following commands will inherit those file descriptors.
Is there a way to change stdout/stderr for the current shell to a pipe?
I've tried
exec | gpg -aer 0x6aabe354
in the hope to replace current stdout with gnupg, encrypting the output of the remaining script, but I received cleartext output and an empty PGP message instead, so clearly this is not the correct syntax.
Simon Richter
(4990 rep)
Feb 28, 2025, 06:56 AM
• Last activity: Feb 28, 2025, 08:06 AM
Showing page 1 of 20 total questions