今日已更新 222 条资讯 | 累计 40667 条内容
关于我们

标签:#ux

找到 282 篇相关文章

AI 资讯

Starting a Linux Group in a Region Where None Existed

A few months ago I got properly bitten by the Linux bug. Ubuntu became my daily driver, I started digging into terminal tools way past the point of “practical necessity,” and I got obsessed with an idea that wouldn’t leave me alone: old hardware doesn’t have to die just because it’s old. I work as an on-site IT coordinator, handling day-to-day IT operations for an industrial company. Between that and years of general sysadmin work, I’ve watched a lot of perfectly usable machines get pulled out of service and shipped off as e-waste — not because they were broken, but because someone decided they were “too old” for whatever OS they were running. A Core 2 Duo with a fresh SSD and a lightweight distro can still be a genuinely useful computer.That gap between “technically obsolete” and “actually still works great” is where a lot of my curiosity lives right now. The gap I kept running into The more I looked into the Norwegian Linux scene, the more I found — Skolelinux/Debian Edu has deep roots here, NUUG (Norwegian Unix User Group) has been active for decades, and there’s a project called PC-Aid that collects, wipes, and reinstalls Debian Edu on used PCs, then sends them to schoolchildren in Ukraine. It’s been running for a few years now, quietly doing real, tangible good. I wanted in. But when I looked for any of this activity near me — Sunnmøre, a district on Norway’s west coast (in Møre og Romsdal county, home to the town of Ålesund) — there was nothing. No local NUUG chapter, no meetup, no group. Just… a gap. (If you’re not from Norway, don’t worry, most Norwegians would need a map for this too.) So instead of waiting for someone else to fill it, I started SLUG — Sunnmøre Linux User Group. Reaching out, awkwardly, like you do Starting a group is the easy part. Getting it to mean anything is harder. So I did the obvious thing: I found people who’d actually been part of PC-Aid and reached out. First was someone who’d been active in the project early on. I sent a message

2026-08-11 原文 →
AI 资讯

Build map guidance that follows the user without blocking pinch-to-zoom

A navigation map should help the user move through the world, not fight every gesture they make. I recently hit a deceptively simple bug while building field guidance in a React Native / Expo app: the route rendered correctly and the camera followed the current position, but users could not meaningfully zoom or pan while walking. They could pinch the map, but the next location update snapped the camera back to a fixed zoom. The map looked active. The experience felt broken. The cause: two camera owners The implementation combined two useful features: followsUserLocation={true} on the native map. animateCamera(...) after every location update, using a fixed walking zoom and pitch. Each feature was reasonable on its own. Together, they gave the camera two automatic owners and the user none. A pinch gesture changed the zoom for a fraction of a second. Then a GPS update arrived and our effect applied the navigation camera again. On iOS, native user-follow behavior added another layer of camera control. A better model: follow mode and explore mode The fix was not to stop navigation. Route progress, distance, bearing, breadcrumb recording and off-route detection should all continue regardless of what the user does with the map. Only the camera behavior should change. We now keep a small piece of local UI state: const [ cameraFollowing , setCameraFollowing ] = useState ( navigationActive ); useEffect (() => { if ( ! navigationActive || ! cameraFollowing || bearing == null ) return ; mapRef . current ?. animateCamera ( walkingCamera ( currentCoordinate , bearing ), { duration : 480 }, ); }, [ currentCoordinate , bearing , navigationActive , cameraFollowing ]); The native follow prop uses the same state: < MapView showsUserLocation followsUserLocation = { navigationActive && cameraFollowing } onTouchStart = { () => { if ( navigationActive ) setCameraFollowing ( false ); } } /> As soon as the user touches the map, the camera enters explore mode. Pinch, pan and rotation work n

2026-08-09 原文 →
AI 资讯

I Turned an Android Phone Into a No-Root Cybersecurity Learning Workspace

I Turned an Android Phone Into a No-Root Cybersecurity Learning Workspace Most people don't look at an Android phone and think: "This could be a practical Linux, Python, networking, and cybersecurity learning environment." Usually, the assumption is that serious technical learning requires a laptop, a virtual machine, or dedicated hardware. I wanted to see how far I could push the opposite idea. What if the Android phone you already own could become a practical learning workspace without root access? That experiment eventually became DedSec . DedSec is a free and open-source project built around Android and Termux. Its goal is not simply to install a large collection of tools. The goal is to create an environment where someone can actually learn how the pieces fit together. Repository: https://github.com/dedsec1121fk/DedSec Official website: https://ded-sec.space/ Why Android? Android devices are incredibly capable machines. Even an older phone can provide: a Linux-like command-line environment through Termux Python Git package management networking utilities file manipulation scripting automation local development workflows And you can do a surprising amount without root access. The limitation isn't always the hardware. A bigger limitation is often knowing what to do with it. You can install dozens of packages, copy commands from tutorials, and still not understand what is actually happening underneath. That was one of the problems I wanted DedSec to address. More Than a Collection of Scripts There are plenty of repositories containing security scripts. That wasn't enough for what I wanted to build. Installing a tool doesn't automatically teach you: what problem the tool solves when you should use it what its output means what layer of the system is failing how networking concepts connect together why a command works why another command fails So DedSec gradually became an ecosystem rather than just a scripts directory. The project connects several things together:

2026-08-08 原文 →
AI 资讯

Docker for Beginners: Images, Containers, Ports, and Volumes Explained

Docker for Beginners: Images, Containers, Ports, and Volumes Explained If you've ever followed a programming tutorial and seen something like: docker run ... you've probably wondered: What exactly is Docker doing? I had the same question when I started learning Docker. At first, I thought Docker was simply a way to "run applications in containers." But there is much more to it. Once I understood four concepts — images, containers, ports, and volumes — Docker became much easier to understand. So let's break it down from the beginning. What Is Docker? Docker is a platform for building, packaging, and running applications in isolated environments called containers . The basic idea is simple: Package an application together with the things it needs to run, and make that package portable. For example, imagine you build a Python application. Your application might depend on: Python 3.12 FastAPI Uvicorn Several Python packages Environment variables Certain system libraries On your computer, everything works. Then someone else downloads your project. They install a different Python version. A package is missing. Something behaves differently. Now you have: "It works on my machine." Docker helps reduce this problem by allowing you to define the environment your application should run in. The Four Concepts You Need to Understand Before learning Docker commands, understand these four things: Docker Image ↓ Docker Container ↓ Ports ↓ Volumes Let's look at each one. 1. What Is a Docker Image? A Docker image is a packaged, read-only template used to create containers. Think of it like a blueprint. For example: Docker Image │ ├── Ubuntu ├── Python ├── Application code ├── Dependencies └── Configuration An image contains the instructions and filesystem needed to create a container. You can download images from container registries such as Docker Hub. For example: docker pull nginx This downloads the Nginx image. You can see your downloaded images with: docker images You might see s

2026-08-08 原文 →
AI 资讯

The Headless Workspace: How Antigravity CLI Lowers the Neovim Learning Curve

A GUI IDE is great for local development, but it quickly falls apart when you transition to headless servers, low-power client machines, or remote clouds. If you pair an AI agent like Antigravity CLI with a native-first Neovim configuration, you can bypass complex setups entirely. Since the AI assistant is the one doing the heavy writing, refactoring, and saving of files, you don't need to be a Vim keyboard wizard to use Neovim. The editor simply becomes a fast, native terminal pane for inspecting the code and reviewing git diffs. By pairing the two, you can build a modern, high-performance workspace built on native features that runs perfectly in any terminal. Here is the backstory of how we ended up with this setup, and why going native-first in Neovim became our preferred remote development tool. 💻 The Backstory: From a Broken Screen to Ephemeral Cloud VMs My 10-year-old MacBook Pro recently had its screen break. It still works fine, but it is now permanently anchored to my desk with an external monitor. Buying a new laptop is too expensive right now, but I have an iPad that I use when traveling. To work from the iPad, I use Google Cloud Shell via the web browser. This allows me to write and inspect code using the Cloud Shell Editor and run Antigravity CLI . However, Cloud Shell has strict storage, memory, and CPU limits. As an Application Modernization, DevOps, and SRE developer, my projects are resource-intensive. I need to run multi-container environments like the Google Cloud Microservices Demo . Plus, next week I’m attending the Gemma Day Event hosted by the Google DeepMind team. This will be my first hands-on contact with Gemma, and after the event, I plan to continue testing how the model interacts inside a Kubernetes cluster, establishing observability for LLM-native metrics (like token throughput and response latency). I don't want to buy an expensive machine with a GPU just to test these setups. Instead, I want to spin up a GPU-enabled VM in Compute Eng

2026-08-08 原文 →
AI 资讯

What Linux actually does when you read a file

I asked Linux for one 4 KiB page from the start of a cold file. Four pages came back. I moved the same read one page further in, ran it again, and got one. Same file, same syscall, same kernel. The only thing that changed was where I started reading, and I spent twenty minutes assuming the tool I'd just written was miscounting. It wasn't. A read that starts at byte zero is treated as a promise. There's a branch in mm/readahead.c that reads, in full, if (!index) goto initial_readahead; . Offset zero means the kernel takes you for a program that's about to stream the whole file, and it fetches ahead immediately. Start anywhere else and you're assumed to be seeking randomly until a pattern proves otherwise. Nothing in my call said a word about my intentions. It inferred them from an offset. I spent two weeks on this sort of thing recently. Not for work, and not toward anything shippable. The short version of what I found is that a surprising amount of the machinery under a running program isn't carrying out instructions at all. It's guessing. The bench , because it changes how you should read every number here: an ext4 filesystem on a loop device, inside an OrbStack Linux VM on an Apple Silicon Mac, kernel 7.0.14, 4 KiB pages, read_ahead_kb at 128. That's a container sharing the host's kernel, not bare metal, and the host reclaims memory aggressively enough that a fully cached file can go cold in fifteen seconds. Reads came from dd ; the page-by-page counting came from a small C tool I wrote that mmap s a file and asks mincore() which of its pages are resident. You're not addressing the disk, you're addressing the page cache The model most of us carry is that read() goes and gets bytes off a device. It doesn't. It copies bytes out of the page cache into your buffer, and the page cache is just RAM the kernel uses to remember parts of files. If what you want is already there, no device is involved. If it isn't, the kernel fills the cache first and then copies. Either way

2026-08-08 原文 →
AI 资讯

A text message that runs a command: OS command injection in Gammu SMSD (GHSA-9vjj-v46c-c5qf)

TL;DR What: Gammu SMSD — the daemon behind a huge number of SMS gateways, alerting rigs and 2FA senders — runs an operator-configured hook every time a text arrives. With the Files backend and RunOnReceive enabled, the SMS sender ID was escaped for use as a filename but not for the shell , and then appended to a /bin/sh -c command line. A sender ID containing shell metacharacters executed arbitrary commands as the gammu-smsd user. Impact: Remote, unauthenticated code execution triggered by sending a text message. Commands run with the daemon's privileges. Missing neutralization of special elements in an OS command (CWE-78). Fixed in: Gammu 1.43.3 . Advisory GHSA-9vjj-v46c-c5qf , published 25 July 2026, rated High (8.1) , credited to me as reporter. CVE requested, pending GitHub assignment. Why you should care Most command-injection bugs need the attacker to already be talking to your HTTP API. This one needs a phone number. Gammu SMSD sits on the receiving end of a modem or GSM dongle. Hospitals use it for on-call paging, monitoring systems use it for SMS alerts, and plenty of small shops use it as the cheap half of a 2FA setup. A very common configuration is: store incoming messages as files (the Files backend ), and run a script whenever one arrives ( RunOnReceive ) — to forward it, log it, or trigger something. The input to that script comes from the outside world over the cellular network. The sender doesn't authenticate to anything. And on many networks the sender ID is an arbitrary alphanumeric string , not a phone number — that's how banks send texts that say "HSBC" instead of a number. Alphanumeric sender IDs are attacker-controllable, and they can carry the exact characters a shell treats as syntax. That is the whole bug: a value from a text message reaches /bin/sh . The setup Gammu SMSD's Files backend writes each received message to a file whose name includes the sender. To keep that filename legal, it runs the sender ID through an escaping function first

2026-08-07 原文 →
AI 资讯

The Same Setting, Three Different Answers: Why 0.0.0.0 Isn't Always What You Want

There is a line in almost every Python web tutorial that nobody explains: uvicorn main:app --host 0.0.0.0 --port 8000 I copied it for weeks without thinking about it. Then I deployed the same application three times — to a local VM, to a production server, and into a container — and the correct value was different every time. Twice it was 0.0.0.0 . Once, in the place that mattered most, it was not. That gap is worth writing about, because the setting itself is trivial and the reasoning behind it is not. What the Flag Actually Controls A server process doesn't "open a port." It creates a socket and binds it to an address. The bind address answers one question: which network interfaces should this socket accept connections from? A machine has more than one interface: lo (loopback) — reachable only from inside the machine ( 127.0.0.1 ). Packets addressed there never reach a physical network card; the kernel loops them straight back. 0.0.0.0 — a wildcard meaning every interface this machine has , including ones added later. So the flag isn't about security or convenience. It's about reachability — and reachability depends entirely on what sits in front of the process. Case 1: The Local VM — 0.0.0.0 I was running the service inside a Multipass VM and wanted to hit it from the browser on my laptop. The laptop is outside the VM, so binding to loopback would have made the service invisible to it. curl inside the VM would work; the browser outside would get connection refused. Decision: wildcard bind. Nothing sits in front of the process, and nothing needs protecting. Case 2: Production — 127.0.0.1 Here I copied the same line at first, and it was wrong. The production box has a public IP. Binding to 0.0.0.0 there means the application is directly exposed to the internet: no TLS, no rate limiting, no authentication. Within hours of provisioning that server, its SSH logs showed hundreds of automated login attempts against usernames like admin and oracle . The same scanners try

2026-08-07 原文 →
AI 资讯

How to Set Up Rate Limiting in Nuxt

Rate limiting is one of those things that doesn't feel urgent—until someone hammers your login endpoint at 3am and you wake up to a flooded database and a locked-out user base. I added this to my Nuxt base layer after realising I'd shipped several projects with zero protection on auth routes. Not great. This post walks through the exact setup I now use: Redis-backed, an in-memory fallback when Redis is down, named presets for different sensitivity levels, and a 429 page that shows a live countdown instead of just dying on the user. The structure Three pieces, each with one job: createRateLimiter() — a factory that builds the limiter, using Redis with an in-memory fallback applyRateLimit() — what you call inside handlers to enforce a limit server/middleware/rateLimiter.ts — global middleware so every route gets a baseline for free 1. Install npm install rate-limiter-flexible ioredis rate-limiter-flexible does the heavy lifting: sliding windows, Redis integration, and the insurance fallback pattern we'll use. 2. The factory Create server/utils/rateLimiter.ts : import { RateLimiterRedis , RateLimiterMemory , type RateLimiterAbstract , } from ' rate-limiter-flexible ' import { getRedisClient } from ' ./redis ' export interface RateLimiterConfig { keyPrefix : string // Must be unique per limiter, e.g. 'rl:auth' limit : number // Maximum requests within the window windowSeconds : number } export interface RateLimitResult { allowed : boolean limit : number remaining : number resetAt : number // Unix timestamp in seconds when the window resets retryAfter : number // Seconds until retry; 0 if allowed } function buildLimiter ( config : RateLimiterConfig , ): RateLimiterAbstract { const insurance = new RateLimiterMemory ({ keyPrefix : config . keyPrefix , points : config . limit , duration : config . windowSeconds , }) const redis = getRedisClient () if ( ! redis ) { return insurance } return new RateLimiterRedis ({ storeClient : redis , keyPrefix : config . keyPrefix , points

2026-08-07 原文 →
AI 资讯

The Privacy Summary Screen — 60 Minutes of Design With Outsized Impact

Most mobile apps ship a privacy policy as a link that opens Safari. A smaller number ship an in-app rendered policy. A tiny minority ship what I think is the single highest-leverage privacy screen: a summary that mirrors your Nutrition Label in plain language, designed to be read. Why it's high-leverage The privacy summary sits at the intersection of three concerns: Users read it before granting sensitive permissions. Especially for camera, contacts, location, and health data. App Store reviewers check it exists and matches your store listing. Regulators (GDPR, CCPA) reward it. Clarity is a compliance signal, not a legal defense — but it's what an investigator asks for first. Sixty minutes of design work. Meaningful trust dividends. Often the difference between first-submission approval and a rejection loop. What to include The privacy summary should mirror your Privacy Nutrition Label but with real language humans can parse: Each data category you collect — displayed as a card or a row, with a clear icon. Why you collect it — one line, plain language. "So you can log in on another device," not "for authentication purposes." Where it's used — is it stored on our servers, shared with third parties, only on your device? Be specific. How to opt out or delete it — a link or a button to the settings page where the user can act on that category. Six to eight cards, one per data category. No more. Visual patterns that read as trustworthy Design choices that consistently score high in user-testing for trust signal: Real language, not legalese. "We store your email address so you can log in" beats "Personal identifiers are retained for authentication purposes." Muted, confident colors. No warning reds, no compliance yellows. A neutral surface with soft accent for the data-category icons. Readable typography. 16pt body, generous line-height (1.5x), enough paragraph spacing that scanning is easy. Icons per category (not just text). A camera icon for camera data, a location pin

2026-08-06 原文 →
AI 资讯

Claude and Figma: bulk edits that don't break your file

I asked an agent to swap one colour value across a file. It did. It also rewrote the line that defined the value in the first place, so the definition now pointed at itself. Nothing errored. Nothing warned. The instruction ran perfectly, which is the whole problem. Every one of these has the same shape A single condition matched more than I meant, and everything that matched got changed. The second one I still think about: hiding a set of shadow rectangles also hid a keyboard, because the keyboard's parts satisfied exactly the same single condition. Again no error, again a clean report of success. Once you see the pattern it's everywhere. It isn't a model being careless. It's an instruction that was less precise than it felt while writing it, executed with total literalness by something that has no idea what any of these objects are for. The rule: scope, and two conditions, never one Name the region it may touch. Not "the file" — this section, these frames, this layer group. Then give it two properties that must both be true. Not "everything with this colour" but "everything with this colour, inside this region, that is a fill rather than a definition". The second condition is doing the real work: it's what stops the match spreading into things that happen to share one attribute. It's a small amount of extra writing. It's the difference between a change and an incident. It cannot see the result — that's the fixed constraint An agent writes the change, the change renders somewhere it has no eyes on, and it reports success based on the instruction completing rather than the outcome being right. People treat that missing feedback loop as a tooling problem, something that will be solved in a future version. I don't think it is one. It's a sequencing problem, and sequencing is available today. The loop can't be closed by the agent. Fine. It can still be closed by a person — just not a hundred times. One, then all Run the operation on a single representative case. Render

2026-08-06 原文 →
AI 资讯

Claude to Figma: keeping AI-generated UI bound to your design system

On one build I found 127 places bound to a raw colour instead of a named role. Every single one had passed visual review. They all surfaced the moment someone asked for dark mode. That number is the whole argument. Not because 127 is large, but because none of them looked wrong. A value that was typed in and a value that came from the system are visually identical. The difference only exists in what happens next. The failure isn't that the agent breaks the rules It's that it extends them. Give an agent a design system and ask it to build. When it reaches something the system covers, it uses the system — genuinely, reliably. When it reaches something the system doesn't cover, it does not stop and ask. It invents. And what it invents is a name that sounds exactly like one of yours, sitting right next to the real ones, reading as though someone chose it on purpose. That's why this is so hard to catch by eye. A fabricated token isn't a glaring error. It's a plausible one. Six months later nobody can tell you whether it was a deliberate exception or a hallucination, and by then five components depend on it. Readable is not the same as closed Making a library available to an agent gets you components it will reuse. It does not get you a closed set. A closed set means: these values exist, everything else does not, and anything outside them fails loudly rather than passing quietly. The distinction sounds pedantic and it decides everything. A readable system produces output that mostly matches. A closed system produces output you can audit. Which is the real test I'd apply to any AI design setup: not how much of your system it covers, but what happens to the things it doesn't cover. If those slip through silently, coverage is irrelevant — you've just made the drift harder to spot. Layers, and not reaching past them Tokens have layers for a reason. Base values underneath — the raw material. Named roles on top — what a value is for. And the product interface binds to the role,

2026-08-06 原文 →
AI 资讯

Figma MCP: turning Claude-generated UI into a component library

This is the stretch nobody films. The demo ends at the screenshot; the job ends about a week later, in a Figma file that someone else has to be able to open without you in the room. It's also where roughly 40% of the work lives, and where most AI-assisted design quietly falls over — not because the screens are bad, but because nothing in them is addressable. Import destroys the names Bring generated markup into Figma and everything arrives as a frame inside a frame inside a frame, with names that mean nothing. The structure survives. The meaning doesn't. The instinct at this point is to start componentising from what's on the canvas — find a button in a screen, make it a component, move on. Don't. That tree is a rendering artefact. Build your library from it and you inherit every accident in it: wrapper divs promoted to components, layout containers baked into masters, the same element modelled three different ways because it appeared in three different screens. The source markup is the specification. It knows what each thing is. So the first move is reading it and producing a record of what should exist and what it should be called — then renaming against that record, then componentising. Rename first, componentise second. Reversing those two costs more than any other ordering mistake in this stage. Library first, screens second Masters get built in a clean library section, not harvested from inside screens. The difference shows up in what ends up inside the component. Harvested masters carry their surroundings — a padding wrapper that belonged to the screen, a demo label, a background that existed to make it visible on a dark canvas. Those things then travel into every instance, and six months later somebody is asking why every card has eight pixels of phantom padding. Same-structure things get grouped into a variant set rather than left as separate components. A button that arrives as five unrelated components instead of one set is the single most common breakage

2026-08-06 原文 →
AI 资讯

The Mindset Behind Hard Debugging

Hard debugging is rarely defeated by a lack of tools. It is defeated by three quiet habits: assuming the fault is where the symptom appears, clinging to the first explanation, and hoping a tool will do the thinking. A difficult fault is usually lost to those habits before you read a line of code. The engineers who resolve hard faults are the ones who notice these defaults and replace them with a patient, evidence-first mindset. Most hard bugs are lost before we touch them, in the attitude we bring to the session. When something breaks, the average person rushes in with three quiet habits: they assume the fault lives exactly where it shows up, they cling to the first explanation their mind offers, and they hope a tool or a smarter person will tell them what to do next. Those habits feel natural, but on hard faults they are exactly what keep us stuck. Put two engineers on the same failing board. One finds a way through in an afternoon; the other is still going three days later. The difference is rarely raw intelligence or how many commands they know. It is the mental posture each brings to the work before the first step. Handling a hard debug session is less about knowing every tool and more about managing your own assumptions, reactions, and impatience. A tough problem is usually lost in your mindset before it is lost in your methods. Habit one: starting too narrow The first habit is to fix on the most visible symptom and refuse to look anywhere else. Something breaks, so we stare at the last thing we changed, and we return to it because it is familiar and close at hand. When the answer is not there, we look harder in the same place instead of stepping back. Here is what that looks like on real hardware. A device keeps dropping off the bus. You are a kernel person, so you open the driver and read it, carefully, for three days: the probe path, the error handling, the power-management callbacks. Every line is correct, and the device still fails. The fault was a layer b

2026-08-06 原文 →
AI 资讯

Linux Troubleshooting Workflow for Beginners: A Step-by-Step Guide

Most Linux problems aren't actually difficult. They're difficult because they're often debugged in the wrong order. Many beginners immediately: Restart services randomly Run commands without a plan Change configurations before understanding the problem Guess instead of observing Experienced engineers do something different. They follow a structured troubleshooting process. This article isn't about learning new Linux commands. It's about knowing when and why to use the commands you've already learned throughout this Linux Beginner Series. Think of it as putting everything together into one practical troubleshooting workflow that's used in real Linux and DevOps environments. Quick Troubleshooting Workflow Observe ↓ Check System Health ↓ Identify Problem Type ↓ Read Logs ↓ Verify Service ↓ Check Network ↓ Check Disk ↓ Recent Changes ↓ Find the Root Cause ↓ Apply the Fix Keep this workflow in mind as you read through the guide. Step 0: Observe Before You Change Anything Before running a single command, pause for a moment. Ask yourself: What exactly is broken? When did the issue start? Is everyone affected or only some users? Is the problem constant or intermittent? What changed recently? Many troubleshooting sessions become longer because people try to fix the problem before they understand it. Good troubleshooting begins with observation, not commands. Step 1: Check Overall System Health Your first goal is to understand the overall health of the system—not to fix anything yet. Useful commands: uptime free -h top Look for: High load average High CPU usage Low available memory Signs that the server is under heavy load At this stage, you're only gathering evidence. A quick system health check often tells you where to investigate next. Step 2: Identify the Type of Problem Before diving deeper, classify the issue. Problem Type Common Symptoms First Commands to Check CPU Slow system, high CPU usage top , htop Memory Applications crashing, OOM kills free -h Disk "No space lef

2026-08-04 原文 →
AI 资讯

A Month With Bash — Part 3: Building Projects

A Month With Bash — Part 3: Building Projects After all the expansions and syntax, I moved on to regex in bash. It wasn't too hard since I'd already worked with regex in Python, but alongside it I learned grep , sed , and awk — tools that turned out to be extremely useful for automation. I built a few mini projects and started automating some of my small day-to-day tasks. I won't go too deep into that here, but you can check out my learning-bash GitHub repo, which has all my learning scripts. From there I covered conditionals, loops, and repetitive tasks. Finally I learned about array variables in bash and shell options, went even further testing different ways of looping, and that's when I started actual project building(I am still building ) #!/usr/bin/env bash ## looping with range functions -- somehow # python style looping {start..end} for i in { 1..10 } ; do # this uses brace expansion so using vars wont work becase of execution sequencing echo $i done clear ## c - slyle looping for (( i = 0 ; i < 10 ; i++ )) ; do # variables works here well echo "hello $i " done ## using variables to loop clear start = 1 stop = 10 step = 2 for i in $( seq $start $stop ) ; do # this uses the seq command echo "hello world" done Conclusion Spending so much time on bash wasn't a waste. Not only did it force me to learn a huge number of commands, it changed how I think about my own machine — most of what I used to do manually, I can now automate. That shift alone made the month worth it. i am still learning and trying to get the best practices and things not to do THANK YOU FOR READING THIS FAR. That is a rough summary of me writing bash for a month there is really a lot left unsaid here but still building and learning. If you are just starting out with bash or if you haven't tried it hope this helps feel free to drop questions advice and corrections

2026-08-04 原文 →
AI 资讯

A Month With Bash — Part 2: Expansions

A Month With Bash — Part 2: Expansions Continuing from where I left off, the next thing I learned was special parameters in bash: "$*" $# $? $@ $N $- $0 Another important concept I picked up is how bash executes shell scripts. Bash is one of those languages that interprets each line as it goes — but it doesn't stop if a line fails. It continues on unless you explicitly set set -o pipefail (or -e , depending on what you want it to catch). Generally, the procedure looks like this: Tokenizing : splitting the line into tokens, usually split using the IFS value. Brace expansion : a mechanism by which arbitrary strings can be generated. echo file { 1,2,3 } .txt ## output: file1.txt file2.txt file3.txt Bash preserves the order from left to right. Tilde expansion : this is where expansion of special symbols takes place. ~ represents the HOME built-in variable ~+ represents PWD , the current working directory and others DIR = ~/Desktop # this is $HOME/Desktop echo " $DIR " Parameter expansion : introduced with the $ symbol. # ${} — the braces can be omitted for normal variables but not for array-type variables Command substitution : very important — it lets you assign the output of a command to a variable, and use commands inside if and for statements. Done with $(command to execute) . week_name = " $( date +%A ) " # gets the current day of the week echo " $week_name " Generally, $() spawns a new shell instance, so it's advisable to avoid it where possible, for latency reasons. Arithmetic expansion : just from the name, this allows evaluation of arithmetic expressions and substitution of the result. It starts with $(( expression )) . There are some rules — bash doesn't support floating point arithmetic natively, so you'd reach for bc if you need it. I won't go deep into that here since this isn't a full bash tutorial. Here's a simple BMI calculator I wrote while practicing this: #!/usr/bin/env bash # script calculates user's BMI and gives a recommendation set -euo pipefail #

2026-08-04 原文 →
AI 资讯

How Much Should Live Together? Learning to Isolate Services the Hard Way

Also Published On trever.cloud Medium LinkedIn Most of us who get into self-hosting start the same way: start with linux, throw a few apps into Docker, get them running and connectable outside the home network, and call it good for months, maybe even years. Nothing wrong with that approach. A compose file and a spare mini PC gets you further than you think, and if it works and you don't have to think about it, that's a perfectly fine place to stop. Then there's the rest of us. The people who get that first setup running, feel the little spark of "wait, I built this", and immediately start wondering what else is possible. More services. Less babysitting. A real answer to "what happens if this box dies at 2am". If any of that sounds familiar, this one's for you. If you keep going, you'll eventually run into the question every self-hosted setup faces sooner or later, whether you notice it happening or not, "how much should live together, and how much should be kept apart?". Put everything on one box and you quickly feel the fragility when one bad update takes everything down with it. Or when nightly backups put services on hold longer and longer. Split everything into its own isolated piece and you've gained resiliency but now manage a lot of moving parts. Most of the actual learning in running infrastructure happens in the space between those two answers. Where you draw that line is where most of the real infrastructure lessons live. Over the years, I've lived through a few different answers to that question in my own homelab, and each one taught me something the previous one couldn't. It started with a large VM, Docker installed, and every service I wanted to self-host running as a container inside. It was the fastest path to "it's actually working", and at the time that was the whole goal. I didn't know yet what I'd eventually want out of this thing, so keeping the infrastructure simple while I figured that out made sense. That setup carried me a long way, and I don

2026-08-03 原文 →